Merge from head
This commit is contained in:
commit
d93a511528
12
Makefile
12
Makefile
@ -243,14 +243,8 @@ cleanworld:
|
||||
# Handle the user-driven targets, using the source relative mk files.
|
||||
#
|
||||
|
||||
.if !(!empty(.MAKEFLAGS:M-n) && ${.MAKEFLAGS:M-n} == "-n")
|
||||
# skip this for -n to avoid changing previous behavior of
|
||||
# 'make -n buildworld' etc. Using -n -n will run it.
|
||||
${TGTS}: .MAKE
|
||||
tinderbox toolchains kernel-toolchains: .MAKE
|
||||
.endif
|
||||
|
||||
${TGTS}:
|
||||
${TGTS}: .PHONY .MAKE
|
||||
${_+_}@cd ${.CURDIR}; ${_MAKE} ${.TARGET}
|
||||
|
||||
# The historic default "all" target creates files which may cause stale
|
||||
@ -259,9 +253,9 @@ ${TGTS}:
|
||||
# if they want the historic behavior.
|
||||
.MAIN: _guard
|
||||
|
||||
_guard:
|
||||
_guard: .PHONY
|
||||
@echo
|
||||
@echo "Explicit target required (use \"all\" for historic behavior)"
|
||||
@echo "Explicit target required. Likely \"${SUBDIR_OVERRIDE:Dall:Ubuildworld}\" is wanted. See build(7)."
|
||||
@echo
|
||||
@false
|
||||
|
||||
|
118
Makefile.inc1
118
Makefile.inc1
@ -50,16 +50,23 @@
|
||||
.include <bsd.arch.inc.mk>
|
||||
.include <bsd.compiler.mk>
|
||||
|
||||
# We must do lib/ and libexec/ before bin/, because if installworld
|
||||
# installs a new /bin/sh, the 'make' command will *immediately*
|
||||
# use that new version. And the new (dynamically-linked) /bin/sh
|
||||
# will expect to find appropriate libraries in /lib and /libexec.
|
||||
#
|
||||
# We must do lib/ and libexec/ before bin/ in case of a mid-install error to
|
||||
# keep the users system reasonably usable. For static->dynamic root upgrades,
|
||||
# we don't want to install a dynamic binary without rtld and the needed
|
||||
# libraries. More commonly, for dynamic root, we don't want to install a
|
||||
# binary that requires a newer library version that hasn't been installed yet.
|
||||
# This ordering is not a guarantee though. The only guarantee of a working
|
||||
# system here would require fine-grained ordering of all components based
|
||||
# on their dependencies.
|
||||
SRCDIR?= ${.CURDIR}
|
||||
.if defined(SUBDIR_OVERRIDE)
|
||||
SUBDIR= ${SUBDIR_OVERRIDE}
|
||||
.else
|
||||
SUBDIR= lib libexec
|
||||
.if make(install*)
|
||||
# Ensure libraries are installed before progressing.
|
||||
SUBDIR+=.WAIT
|
||||
.endif
|
||||
SUBDIR+=bin
|
||||
.if ${MK_CDDL} != "no"
|
||||
SUBDIR+=cddl
|
||||
@ -85,10 +92,6 @@ SUBDIR+= tests
|
||||
.if ${MK_OFED} != "no"
|
||||
SUBDIR+=contrib/ofed
|
||||
.endif
|
||||
#
|
||||
# We must do etc/ last for install/distribute to work.
|
||||
#
|
||||
SUBDIR+=etc
|
||||
|
||||
# Local directories are last, since it is nice to at least get the base
|
||||
# system rebuilt before you do them.
|
||||
@ -112,6 +115,15 @@ SUBDIR+= ${_DIR}
|
||||
.endfor
|
||||
.endif
|
||||
|
||||
# We must do etc/ last as it hooks into building the man whatis file
|
||||
# by calling 'makedb' in share/man. This is only relevant for
|
||||
# install/distribute so they build the whatis file after every manpage is
|
||||
# installed.
|
||||
.if make(install*)
|
||||
SUBDIR+=.WAIT
|
||||
.endif
|
||||
SUBDIR+=etc
|
||||
|
||||
.if defined(NOCLEAN)
|
||||
NO_CLEAN= ${NOCLEAN}
|
||||
.endif
|
||||
@ -136,14 +148,17 @@ OSRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \
|
||||
.else
|
||||
OSRELDATE= 0
|
||||
.endif
|
||||
.export OSRELDATE
|
||||
.endif
|
||||
|
||||
# Set VERSION for CTFMERGE to use via the default CTFFLAGS=-L VERSION.
|
||||
.if !defined(VERSION)
|
||||
REVISION!= ${MAKE} -C ${SRCDIR}/release -V REVISION
|
||||
BRANCH!= ${MAKE} -C ${SRCDIR}/release -V BRANCH
|
||||
SRCRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \
|
||||
${SRCDIR}/sys/sys/param.h
|
||||
VERSION= FreeBSD ${REVISION}-${BRANCH:C/-p[0-9]+$//} ${TARGET_ARCH} ${SRCRELDATE}
|
||||
.export VERSION
|
||||
.endif
|
||||
|
||||
KNOWN_ARCHES?= aarch64/arm64 amd64 arm armeb/arm armv6/arm armv6hf/arm i386 i386/pc98 mips mipsel/mips mips64el/mips mips64/mips mipsn32el/mips mipsn32/mips powerpc powerpc64/powerpc sparc64
|
||||
@ -252,7 +267,6 @@ CROSSENV+= ${TARGET_CFLAGS}
|
||||
BMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \
|
||||
PATH=${BPATH}:${PATH} \
|
||||
WORLDTMP=${WORLDTMP} \
|
||||
VERSION="${VERSION}" \
|
||||
MAKEFLAGS="-m ${.CURDIR}/tools/build/mk ${.MAKEFLAGS}"
|
||||
# need to keep this in sync with targets/pseudo/bootstrap-tools/Makefile
|
||||
BSARGS= DESTDIR= \
|
||||
@ -289,8 +303,7 @@ XMAKE= TOOLS_PREFIX=${WORLDTMP} ${BMAKE} \
|
||||
# kernel-tools stage
|
||||
KTMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \
|
||||
PATH=${BPATH}:${PATH} \
|
||||
WORLDTMP=${WORLDTMP} \
|
||||
VERSION="${VERSION}"
|
||||
WORLDTMP=${WORLDTMP}
|
||||
KTMAKE= TOOLS_PREFIX=${WORLDTMP} MAKEOBJDIRPREFIX=${WORLDTMP} \
|
||||
${KTMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \
|
||||
DESTDIR= \
|
||||
@ -303,7 +316,6 @@ KTMAKE= TOOLS_PREFIX=${WORLDTMP} MAKEOBJDIRPREFIX=${WORLDTMP} \
|
||||
# world stage
|
||||
WMAKEENV= ${CROSSENV} \
|
||||
_LDSCRIPTROOT= \
|
||||
VERSION="${VERSION}" \
|
||||
INSTALL="sh ${.CURDIR}/tools/install.sh" \
|
||||
PATH=${TMPPATH}
|
||||
|
||||
@ -313,10 +325,6 @@ HMAKE= PATH=${TMPPATH} ${MAKE} LOCAL_MTREE=${LOCAL_MTREE:Q}
|
||||
HMAKE+= PATH=${TMPPATH} METALOG=${METALOG} -DNO_ROOT
|
||||
.endif
|
||||
|
||||
.if ${MK_CDDL} == "no"
|
||||
WMAKEENV+= MK_CTF=no
|
||||
.endif
|
||||
|
||||
.if defined(CROSS_TOOLCHAIN)
|
||||
LOCALBASE?= /usr/local
|
||||
.include "${LOCALBASE}/share/toolchains/${CROSS_TOOLCHAIN}.mk"
|
||||
@ -446,7 +454,6 @@ LIB32FLAGS+= --sysroot=${WORLDTMP}
|
||||
# Yes, the flags are redundant.
|
||||
LIB32WMAKEENV+= MAKEOBJDIRPREFIX=${LIB32_OBJTREE} \
|
||||
_LDSCRIPTROOT=${LIB32TMP} \
|
||||
VERSION="${VERSION}" \
|
||||
INSTALL="sh ${.CURDIR}/tools/install.sh" \
|
||||
PATH=${TMPPATH} \
|
||||
LIBDIR=/usr/lib32 \
|
||||
@ -557,6 +564,11 @@ _worldtmp:
|
||||
mkdir -p ${WORLDTMP}${TESTSBASE}
|
||||
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \
|
||||
-p ${WORLDTMP}${TESTSBASE} >/dev/null
|
||||
.if ${MK_DEBUG_FILES} != "no"
|
||||
mkdir -p ${WORLDTMP}/usr/lib/debug/${TESTSBASE}
|
||||
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \
|
||||
-p ${WORLDTMP}/usr/lib/debug/${TESTSBASE} >/dev/null
|
||||
.endif
|
||||
.endif
|
||||
.for _mtree in ${LOCAL_MTREE}
|
||||
mtree -deU -f ${.CURDIR}/${_mtree} -p ${WORLDTMP} > /dev/null
|
||||
@ -579,9 +591,9 @@ _cleanobj:
|
||||
@echo "--------------------------------------------------------------"
|
||||
@echo ">>> stage 2.1: cleaning up the object tree"
|
||||
@echo "--------------------------------------------------------------"
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} ${CLEANDIR:S/^/par-/}
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} ${CLEANDIR}
|
||||
.if defined(LIB32TMP)
|
||||
${_+_}cd ${.CURDIR}; ${LIB32WMAKE} -f Makefile.inc1 ${CLEANDIR:S/^/par-/}
|
||||
${_+_}cd ${.CURDIR}; ${LIB32WMAKE} -f Makefile.inc1 ${CLEANDIR}
|
||||
.endif
|
||||
.endif
|
||||
_obj:
|
||||
@ -589,7 +601,7 @@ _obj:
|
||||
@echo "--------------------------------------------------------------"
|
||||
@echo ">>> stage 2.2: rebuilding the object tree"
|
||||
@echo "--------------------------------------------------------------"
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} par-obj
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} obj
|
||||
_build-tools:
|
||||
@echo
|
||||
@echo "--------------------------------------------------------------"
|
||||
@ -608,7 +620,8 @@ _includes:
|
||||
@echo "--------------------------------------------------------------"
|
||||
@echo ">>> stage 4.1: building includes"
|
||||
@echo "--------------------------------------------------------------"
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} SHARED=symlinks par-includes
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} SHARED=symlinks buildincludes
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} SHARED=symlinks installincludes
|
||||
_libraries:
|
||||
@echo
|
||||
@echo "--------------------------------------------------------------"
|
||||
@ -622,7 +635,7 @@ _depend:
|
||||
@echo "--------------------------------------------------------------"
|
||||
@echo ">>> stage 4.3: make dependencies"
|
||||
@echo "--------------------------------------------------------------"
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} par-depend
|
||||
${_+_}cd ${.CURDIR}; ${WMAKE} depend
|
||||
everything:
|
||||
@echo
|
||||
@echo "--------------------------------------------------------------"
|
||||
@ -731,7 +744,7 @@ buildworld_epilogue:
|
||||
# to quote multiword values.
|
||||
#
|
||||
buildenvvars:
|
||||
@echo ${WMAKEENV:Q}
|
||||
@echo ${WMAKEENV:Q} ${.MAKE.EXPORTED:@v@$v=\"${$v}\"@}
|
||||
|
||||
.if ${.TARGETS:Mbuildenv}
|
||||
.if ${.MAKEFLAGS:M-j}
|
||||
@ -815,7 +828,7 @@ _zoneinfo= zic tzsetup
|
||||
|
||||
ITOOLS= [ awk cap_mkdb cat chflags chmod chown cmp cp \
|
||||
date echo egrep find grep id install ${_install-info} \
|
||||
ln lockf make mkdir mtree mv pwd_mkdb \
|
||||
ln make mkdir mtree mv pwd_mkdb \
|
||||
rm sed services_mkdb sh strip sysctl test true uname wc ${_zoneinfo} \
|
||||
${LOCAL_ITOOLS}
|
||||
|
||||
@ -892,6 +905,10 @@ distributeworld installworld: _installcheck_world
|
||||
-mkdir -p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE}
|
||||
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \
|
||||
-p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE} >/dev/null
|
||||
.if ${MK_DEBUG_FILES} != "no"
|
||||
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \
|
||||
-p ${DESTDIR}/${DISTDIR}/${dist}/usr/lib/debug/${TESTSBASE} >/dev/null
|
||||
.endif
|
||||
.endif
|
||||
.if defined(NO_ROOT)
|
||||
${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.root.dist | \
|
||||
@ -1054,7 +1071,7 @@ INSTALLKERNEL= ${_kernel}
|
||||
.endif
|
||||
.endfor
|
||||
|
||||
buildkernel ${WMAKE_TGTS} ${.ALLTARGETS:M_*}: .MAKE
|
||||
buildkernel ${WMAKE_TGTS:N_worldtmp:Nbuild32} ${.ALLTARGETS:M_*:N_worldtmp}: .MAKE .PHONY
|
||||
|
||||
#
|
||||
# buildkernel
|
||||
@ -1485,7 +1502,7 @@ build-tools: .MAKE
|
||||
#
|
||||
# kernel-tools: Build kernel-building tools
|
||||
#
|
||||
kernel-tools: .MAKE
|
||||
kernel-tools:
|
||||
mkdir -p ${MAKEOBJDIRPREFIX}/usr
|
||||
mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \
|
||||
-p ${MAKEOBJDIRPREFIX}/usr >/dev/null
|
||||
@ -1566,7 +1583,6 @@ cross-tools: .MAKE
|
||||
|
||||
NXBENV= MAKEOBJDIRPREFIX=${OBJTREE}/nxb \
|
||||
INSTALL="sh ${.CURDIR}/tools/install.sh" \
|
||||
VERSION="${VERSION}" \
|
||||
PATH=${PATH}:${OBJTREE}/gperf_for_gcc/usr/bin
|
||||
NXBMAKE= ${NXBENV} ${MAKE} \
|
||||
TBLGEN=${OBJTREE}/nxb-bin/usr/bin/tblgen \
|
||||
@ -1585,7 +1601,7 @@ NXBMAKE= ${NXBENV} ${MAKE} \
|
||||
# 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
|
||||
native-xtools:
|
||||
.if ${MK_GCC_BOOTSTRAP} != "no"
|
||||
mkdir -p ${OBJTREE}/gperf_for_gcc/usr/bin
|
||||
${_+_}@${ECHODIR} "===> ${_gperf} (obj,depend,all,install)"; \
|
||||
@ -1931,22 +1947,18 @@ _startup_libs: ${_startup_libs:S/$/__L/}
|
||||
_prebuild_libs: ${_prebuild_libs:S/$/__L/}
|
||||
_generic_libs: ${_generic_libs:S/$/__L/}
|
||||
|
||||
.for __target in all clean cleandepend cleandir depend includes obj
|
||||
.for entry in ${SUBDIR}
|
||||
${entry}.${__target}__D: .PHONY .MAKE
|
||||
${_+_}@set -e; if test -d ${.CURDIR}/${entry}.${MACHINE_ARCH}; then \
|
||||
${ECHODIR} "===> ${DIRPRFX}${entry}.${MACHINE_ARCH} (${__target})"; \
|
||||
edir=${entry}.${MACHINE_ARCH}; \
|
||||
cd ${.CURDIR}/$${edir}; \
|
||||
else \
|
||||
${ECHODIR} "===> ${DIRPRFX}${entry} (${__target})"; \
|
||||
edir=${entry}; \
|
||||
cd ${.CURDIR}/$${edir}; \
|
||||
fi; \
|
||||
${MAKE} ${__target} DIRPRFX=${DIRPRFX}$${edir}/
|
||||
.endfor
|
||||
par-${__target}: ${SUBDIR:S/$/.${__target}__D/}
|
||||
.endfor
|
||||
# Enable SUBDIR_PARALLEL when not calling 'make all', unless called as
|
||||
# 'par-all'. This is because it is unlikely that running 'make all' from
|
||||
# the top-level, especially with a SUBDIR_OVERRIDE or LOCAL_DIRS set,
|
||||
# will have a reliable build if SUBDIRs are built in parallel. This is
|
||||
# safe for the world stage of buildworld though since it has already
|
||||
# built libraries in a proper order and installed includes into WORLDTMP.
|
||||
# Special handling is done for SUBDIR ordering for 'install*' to avoid
|
||||
# trashing a system if it crashes mid-install.
|
||||
par-all: all .PHONY
|
||||
.if !make(all)
|
||||
SUBDIR_PARALLEL=
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
||||
@ -1988,6 +2000,13 @@ delete-old-files:
|
||||
chflags noschg "${DESTDIR}/$${file}" 2>/dev/null || true; \
|
||||
rm ${RM_I} "${DESTDIR}/$${file}" <&3; \
|
||||
fi; \
|
||||
for ext in debug symbols; do \
|
||||
if ! [ -e "${DESTDIR}/$${file}" ] && [ -f \
|
||||
"${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \
|
||||
rm ${RM_I} "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" \
|
||||
<&3; \
|
||||
fi; \
|
||||
done; \
|
||||
done
|
||||
# Remove catpages without corresponding manpages.
|
||||
@exec 3<&0; \
|
||||
@ -2010,6 +2029,11 @@ check-old-files:
|
||||
if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \
|
||||
echo "${DESTDIR}/$${file}"; \
|
||||
fi; \
|
||||
for ext in debug symbols; do \
|
||||
if [ -f "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \
|
||||
echo "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}"; \
|
||||
fi; \
|
||||
done; \
|
||||
done
|
||||
# Check for catpages without corresponding manpages.
|
||||
@find ${DESTDIR}/usr/share/man/cat* ! -type d | \
|
||||
@ -2242,7 +2266,9 @@ _xi-cross-tools:
|
||||
.endfor
|
||||
|
||||
_xi-includes:
|
||||
${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 par-includes \
|
||||
${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 buildincludes \
|
||||
DESTDIR=${XDDESTDIR}
|
||||
${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 installincludes \
|
||||
DESTDIR=${XDDESTDIR}
|
||||
|
||||
_xi-libraries:
|
||||
|
@ -97,6 +97,410 @@ OLD_FILES+=usr/bin/colldef
|
||||
OLD_FILES+=usr/share/man/man1/colldef.1.gz
|
||||
OLD_FILES+=usr/bin/mklocale
|
||||
OLD_FILES+=usr/share/man/man1/mklocale.1.gz
|
||||
# 20151015: test symbols moved to /usr/lib/debug
|
||||
OLD_DIRS+=usr/tests/lib/atf/libatf-c++/.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/atf_c++_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/build_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/check_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/config_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/macros_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/tests_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/.debug/utils_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/atf/libatf-c++/detail/.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/application_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/env_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/exceptions_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/fs_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/process_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/sanity_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/text_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/.debug/version_helper.debug
|
||||
OLD_DIRS+=usr/tests/lib/atf/libatf-c/.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/atf_c_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/build_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/check_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/config_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/error_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/macros_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/tc_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/tp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/.debug/utils_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/atf/libatf-c/detail/.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/dynstr_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/env_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/fs_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/list_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/map_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/process_helpers.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/process_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/sanity_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/text_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/user_test.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/.debug/version_helper.debug
|
||||
OLD_DIRS+=usr/tests/lib/atf/test-programs/.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/test-programs/.debug/c_helpers.debug
|
||||
OLD_FILES+=usr/tests/lib/atf/test-programs/.debug/cpp_helpers.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/c063/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/faccessat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fchmodat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fchownat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fexecve.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/fstatat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/linkat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mkdirat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mkfifoat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/mknodat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/openat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/readlinkat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/renameat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/symlinkat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/unlinkat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/c063/.debug/utimensat.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/db/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/db/.debug/h_db.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/gen/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/alarm_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/arc4random_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/assert_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/basedirname_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/dir_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/floatunditf_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fnmatch_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpclassify2_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpclassify_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpsetmask_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/fpsetround_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/ftok_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/getcwd_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/getgrent_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/glob_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/humanize_number_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/isnan_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/nice_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/pause_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/raise_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/realpath_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/setdomainname_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/sethostname_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/sleep_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/syslog_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/time_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/ttyname_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/.debug/vis_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/gen/execve/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/execve/.debug/execve_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/gen/posix_spawn/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/fileactions_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_fileactions.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_spawn.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/h_spawnattr.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/spawn_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/gen/posix_spawn/.debug/spawnattr_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/hash/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/hash/.debug/h_hash.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/hash/.debug/sha2_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/inet/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/inet/.debug/inet_network_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/locale/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/io_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbrtowc_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbsnrtowcs_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbstowcs_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/mbtowc_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcscspn_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcspbrk_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcsspn_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wcstod_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/locale/.debug/wctomb_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/net/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/ether_aton_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/getprotoent_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_dns_server.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_nsd_recurse.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_protoent.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/net/.debug/h_servent.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/regex/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/regex/.debug/exhaust_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/regex/.debug/h_regex.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/regex/.debug/regex_att_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/ssp/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_fgets.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_getcwd.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_gets.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memcpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memmove.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_memset.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_raw.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_read.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_readlink.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_snprintf.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_sprintf.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_stpcpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_stpncpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strcat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strcpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strncat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_strncpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_vsnprintf.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ssp/.debug/h_vsprintf.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/stdio/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/clearerr_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fflush_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fmemopen2_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fmemopen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fopen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/fputc_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/mktemp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/popen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/printf_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdio/.debug/scanf_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/stdlib/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/abs_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/atoi_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/div_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/exit_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/getenv_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/h_getopt.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/h_getopt_long.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/hsearch_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/posix_memalign_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/random_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/strtod_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/strtol_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/stdlib/.debug/system_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/string/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/memchr.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/memcpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/memmem.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/memset.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcat.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strchr.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcmp.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcpy.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strcspn.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strerror.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strlen.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strpbrk.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strrchr.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/strspn.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/string/.debug/swab.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/sys/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/access_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/chroot_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/clock_gettime_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/connect_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/dup_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/fsync_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getcontext_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getgroups_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getitimer_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getlogin_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getpid_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getrusage_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/getsid_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/gettimeofday_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/issetugid_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/kevent_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/kill_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/link_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/listen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mincore_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mkdir_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mkfifo_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mknod_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mlock_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mmap_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/mprotect_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgctl_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgget_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgrcv_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msgsnd_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/msync_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/nanosleep_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/pipe2_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/pipe_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/poll_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/revoke_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/select_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/setrlimit_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/setuid_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigaction_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigqueue_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/sigtimedwait_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/socketpair_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/stat_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/timer_create_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/truncate_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/ucontext_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/umask_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/unlink_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/sys/.debug/write_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/termios/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/termios/.debug/tcsetpgrp_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/tls/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/tls/.debug/h_tls_dlopen.so.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/tls/.debug/libh_tls_dynamic.so.1.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/tls/.debug/tls_dlopen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/tls/.debug/tls_dynamic_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libc/ttyio/.debug
|
||||
OLD_FILES+=usr/tests/lib/libc/ttyio/.debug/ttyio_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libcrypt/.debug
|
||||
OLD_FILES+=usr/tests/lib/libcrypt/.debug/crypt_tests.debug
|
||||
OLD_DIRS+=usr/tests/lib/libmp/.debug
|
||||
OLD_FILES+=usr/tests/lib/libmp/.debug/legacy_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libnv/.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/dnv_tests.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nv_array_tests.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nv_tests.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_add_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_exists_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_free_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_get_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_move_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libnv/.debug/nvlist_send_recv_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libpam/.debug
|
||||
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_ctype.debug
|
||||
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_readlinev.debug
|
||||
OLD_FILES+=usr/tests/lib/libpam/.debug/t_openpam_readword.debug
|
||||
OLD_DIRS+=usr/tests/lib/libproc/.debug
|
||||
OLD_FILES+=usr/tests/lib/libproc/.debug/proc_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libproc/.debug/target_prog.debug
|
||||
OLD_DIRS+=usr/tests/lib/librt/.debug
|
||||
OLD_FILES+=usr/tests/lib/librt/.debug/sched_test.debug
|
||||
OLD_FILES+=usr/tests/lib/librt/.debug/sem_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libthr/.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/barrier_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/cond_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/condwait_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/detach_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/equal_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/fork_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/fpu_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/h_atexit.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/h_cancel.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/h_exit.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/h_resolv.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/join_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/kill_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/mutex_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/once_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/preempt_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/rwlock_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/sem_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/siglongjmp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/sigmask_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/sigsuspend_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/sleep_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/.debug/swapcontext_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libthr/dlopen/.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/dlopen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/h_pthread_dlopen.so.1.debug
|
||||
OLD_FILES+=usr/tests/lib/libthr/dlopen/.debug/main_pthread_create_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libutil/.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/flopen_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/grp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/humanize_number_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/pidfile_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/trimdomain-nodomain_test.debug
|
||||
OLD_FILES+=usr/tests/lib/libutil/.debug/trimdomain_test.debug
|
||||
OLD_DIRS+=usr/tests/lib/libxo/.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/libenc_test.so.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_01.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_02.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_03.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_04.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_05.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_06.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_07.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_08.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_09.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_10.debug
|
||||
OLD_FILES+=usr/tests/lib/libxo/.debug/test_11.debug
|
||||
OLD_DIRS+=usr/tests/lib/msun/.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/acos_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/asin_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/atan_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/cbrt_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/ceil_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/cos_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/cosh_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/erf_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/exp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/fmod_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/infinity_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/ldexp_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/log_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/pow_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/precision_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/round_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/scalbn_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/sin_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/sinh_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/sqrt_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/tan_test.debug
|
||||
OLD_FILES+=usr/tests/lib/msun/.debug/tanh_test.debug
|
||||
OLD_DIRS+=usr/tests/libexec/rtld-elf/.debug
|
||||
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/ld_library_pathfds.debug
|
||||
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/libpythagoras.so.0.debug
|
||||
OLD_FILES+=usr/tests/libexec/rtld-elf/.debug/target.debug
|
||||
OLD_DIRS+=usr/tests/sbin/devd/.debug
|
||||
OLD_FILES+=usr/tests/sbin/devd/.debug/client_test.debug
|
||||
OLD_DIRS+=usr/tests/sbin/dhclient/.debug
|
||||
OLD_FILES+=usr/tests/sbin/dhclient/.debug/option-domain-search_test.debug
|
||||
OLD_DIRS+=usr/tests/share/examples/tests/atf/.debug
|
||||
OLD_FILES+=usr/tests/share/examples/tests/atf/.debug/printf_test.debug
|
||||
OLD_DIRS+=usr/tests/share/examples/tests/plain/.debug
|
||||
OLD_FILES+=usr/tests/share/examples/tests/plain/.debug/printf_test.debug
|
||||
OLD_DIRS+=usr/tests/sys/aio/.debug
|
||||
OLD_FILES+=usr/tests/sys/aio/.debug/aio_kqueue_test.debug
|
||||
OLD_FILES+=usr/tests/sys/aio/.debug/aio_test.debug
|
||||
OLD_FILES+=usr/tests/sys/aio/.debug/lio_kqueue_test.debug
|
||||
OLD_DIRS+=usr/tests/sys/fifo/.debug
|
||||
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_create.debug
|
||||
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_io.debug
|
||||
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_misc.debug
|
||||
OLD_FILES+=usr/tests/sys/fifo/.debug/fifo_open.debug
|
||||
OLD_DIRS+=usr/tests/sys/file/.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/closefrom_test.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/dup_test.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/fcntlflags_test.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/flock_helper.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/ftruncate_test.debug
|
||||
OLD_FILES+=usr/tests/sys/file/.debug/newfileops_on_fork_test.debug
|
||||
OLD_DIRS+=usr/tests/sys/kern/.debug
|
||||
OLD_FILES+=usr/tests/sys/kern/.debug/kern_descrip_test.debug
|
||||
OLD_FILES+=usr/tests/sys/kern/.debug/ptrace_test.debug
|
||||
OLD_FILES+=usr/tests/sys/kern/.debug/unix_seqpacket_test.debug
|
||||
OLD_DIRS+=usr/tests/sys/kern/execve/.debug
|
||||
OLD_FILES+=usr/tests/sys/kern/execve/.debug/execve_helper.debug
|
||||
OLD_FILES+=usr/tests/sys/kern/execve/.debug/good_aout.debug
|
||||
OLD_DIRS+=usr/tests/sys/kqueue/.debug
|
||||
OLD_FILES+=usr/tests/sys/kqueue/.debug/kqtest.debug
|
||||
OLD_DIRS+=usr/tests/sys/mqueue/.debug
|
||||
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest1.debug
|
||||
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest2.debug
|
||||
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest3.debug
|
||||
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest4.debug
|
||||
OLD_FILES+=usr/tests/sys/mqueue/.debug/mqtest5.debug
|
||||
OLD_DIRS+=usr/tests/sys/netinet/.debug
|
||||
OLD_FILES+=usr/tests/sys/netinet/.debug/udp_dontroute.debug
|
||||
OLD_DIRS+=usr/tests/sys/pjdfstest/.debug
|
||||
OLD_FILES+=usr/tests/sys/pjdfstest/.debug/pjdfstest.debug
|
||||
OLD_DIRS+=usr/tests/sys/vm/.debug
|
||||
OLD_FILES+=usr/tests/sys/vm/.debug/mmap_test.debug
|
||||
# 20151015: Rename files due to file-installed-as-dir bug
|
||||
OLD_FILES+=usr/share/doc/legal/realtek
|
||||
OLD_FILES+=usr/share/doc/legal/realtek/LICENSE
|
||||
OLD_DIRS+=usr/share/doc/legal/realtek
|
||||
OLD_DIRS+=usr/share/doc/legal/intel_ipw
|
||||
OLD_FILES+=usr/share/doc/legal/intel_ipw/LICENSE
|
||||
OLD_FILES+=usr/share/doc/legal/intel_iwn
|
||||
OLD_FILES+=usr/share/doc/legal/intel_iwn/LICENSE
|
||||
OLD_DIRS+=usr/share/doc/legal/intel_iwn
|
||||
OLD_DIRS+=usr/share/doc/legal/intel_iwi
|
||||
OLD_FILES+=usr/share/doc/legal/intel_iwi/LICENSE
|
||||
OLD_DIRS+=usr/share/doc/legal/intel_wpi
|
||||
OLD_FILES+=usr/share/doc/legal/intel_wpi/LICENSE
|
||||
# 20151006: new libc++ import
|
||||
OLD_FILES+=usr/include/c++/__tuple_03
|
||||
# 20151006: new clang import which bumps version from 3.6.1 to 3.7.0.
|
||||
|
6
UPDATING
6
UPDATING
@ -31,6 +31,12 @@ 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".)
|
||||
|
||||
20151017:
|
||||
The build previously allowed using 'make -n' to not recurse into
|
||||
sub-directories while showing what commands would be executed, and
|
||||
'make -n -n' to recursively show commands. Now 'make -n' will recurse
|
||||
and 'make -N' will not.
|
||||
|
||||
20151012:
|
||||
If you specify SENDMAIL_MC or SENDMAIL_CF in make.conf, mergemaster
|
||||
and etcupdate will now use this file. A custom sendmail.cf is now
|
||||
|
@ -1,6 +1,8 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
# $FreeBSD$
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
PROG= dd
|
||||
SRCS= args.c conv.c conv_tab.c dd.c misc.c position.c
|
||||
|
||||
@ -24,4 +26,8 @@ test: ${PROG} gen
|
||||
.endfor
|
||||
@rm -f gen
|
||||
|
||||
.if ${MK_TESTS} != "no"
|
||||
SUBDIR+= tests
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
7
bin/dd/tests/Makefile
Normal file
7
bin/dd/tests/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
NETBSD_ATF_TESTS_SH= dd_test
|
||||
|
||||
.include <netbsd-tests.test.mk>
|
||||
|
||||
.include <bsd.test.mk>
|
@ -11,6 +11,6 @@ SRCS= fmt.c keyword.c nlist.c print.c ps.c
|
||||
# on large systems.
|
||||
#
|
||||
CFLAGS+=-DLAZY_PS
|
||||
LIBADD= m kvm jail xo util
|
||||
LIBADD= m kvm jail xo
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -10,4 +10,6 @@ TESTS_SUBDIRS+= parameters
|
||||
TESTS_SUBDIRS+= parser
|
||||
TESTS_SUBDIRS+= set-e
|
||||
|
||||
SUBDIR_PARALLEL=
|
||||
|
||||
.include <bsd.test.mk>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#-
|
||||
# Copyright (c) June 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
|
||||
# All rights reserved.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@ -31,7 +31,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
# force a specified test program, e.g. `env test=/bin/test sh regress.sh'
|
||||
: ${test=test}
|
||||
: ${test=test}
|
||||
|
||||
t ()
|
||||
{
|
||||
@ -54,13 +54,13 @@ t ()
|
||||
count=0
|
||||
echo "1..130"
|
||||
|
||||
t 0 'b = b'
|
||||
t 0 'b == b'
|
||||
t 1 'b != b'
|
||||
t 0 '\( b = b \)'
|
||||
t 0 '\( b == b \)'
|
||||
t 1 '! \( b = b \)'
|
||||
t 1 '! \( b == b \)'
|
||||
t 0 'b = b'
|
||||
t 0 'b == b'
|
||||
t 1 'b != b'
|
||||
t 0 '\( b = b \)'
|
||||
t 0 '\( b == b \)'
|
||||
t 1 '! \( b = b \)'
|
||||
t 1 '! \( b == b \)'
|
||||
t 1 '! -f /etc/passwd'
|
||||
|
||||
t 0 '-h = -h'
|
||||
|
@ -2,10 +2,13 @@
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
SUBDIR= lib sbin usr.bin usr.sbin
|
||||
SUBDIR= lib .WAIT \
|
||||
sbin usr.bin usr.sbin
|
||||
|
||||
.if ${MK_TESTS} != "no"
|
||||
SUBDIR+=tests
|
||||
.endif
|
||||
|
||||
SUBDIR_PARALLEL=
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
@ -18,7 +18,7 @@
|
||||
.\" information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
.\"
|
||||
.\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved.
|
||||
.\" Copyright (c) 2014 by Delphix. All rights reserved.
|
||||
.\" Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
|
||||
.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
|
||||
@ -117,7 +117,7 @@
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
|
||||
.Nm
|
||||
.Cm set
|
||||
.Ar property Ns = Ns Ar value
|
||||
.Ar property Ns = Ns Ar value Oc ...
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
|
||||
.Nm
|
||||
.Cm get
|
||||
@ -189,17 +189,25 @@
|
||||
.Op Fl i Ar snapshot Ns | Ns bookmark
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
|
||||
.Nm
|
||||
.Cm send
|
||||
.Op Fl Penv
|
||||
.Fl t Ar receive_resume_token
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Op Fl vnFu
|
||||
.Op Fl vnsFu
|
||||
.Op Fl o Sy origin Ns = Ns Ar snapshot
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Op Fl vnFu
|
||||
.Op Fl vnsFu
|
||||
.Op Fl d | e
|
||||
.Op Fl o Sy origin Ns = Ns Ar snapshot
|
||||
.Ar filesystem
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Fl A
|
||||
.Ar filesystem Ns | Ns Ar volume
|
||||
.Nm
|
||||
.Cm allow
|
||||
.Ar filesystem Ns | Ns Ar volume
|
||||
.Nm
|
||||
@ -597,6 +605,13 @@ For cloned file systems or volumes, the snapshot from which the clone was
|
||||
created. See also the
|
||||
.Sy clones
|
||||
property.
|
||||
.It Sy receive_resume_token
|
||||
For filesystems or volumes which have saved partially-completed state from
|
||||
.Sy zfs receive -s ,
|
||||
this opaque token can be provided to
|
||||
.Sy zfs send -t
|
||||
to resume and complete the
|
||||
.Sy zfs receive .
|
||||
.It Sy referenced
|
||||
The amount of data that is accessible by this dataset, which may or may not be
|
||||
shared with other datasets in the pool. When a snapshot or clone is created, it
|
||||
@ -2106,14 +2121,14 @@ option, but sorts by property in descending order.
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm set
|
||||
.Ar property Ns = Ns Ar value
|
||||
.Ar property Ns = Ns Ar value Oc ...
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
|
||||
.Xc
|
||||
.Pp
|
||||
Sets the property to the given value for each dataset. Only some properties can
|
||||
be edited. See the "Properties" section for more information on what properties
|
||||
can be set and acceptable values. Numeric values can be specified as exact
|
||||
values, or in a human-readable form with a suffix of
|
||||
Sets the property or list of properties to the given value(s) for each dataset.
|
||||
Only some properties can be edited. See the "Properties" section for more
|
||||
information on what properties can be set and acceptable values. Numeric values
|
||||
can be specified as exact values, or in a human-readable form with a suffix of
|
||||
.Sy B , K , M , G , T , P , E , Z
|
||||
(for bytes, kilobytes, megabytes, gigabytes, terabytes, petabytes, exabytes, or
|
||||
zettabytes, respectively). User properties can be set on snapshots. For more
|
||||
@ -2630,6 +2645,9 @@ useful in conjunction with the
|
||||
or
|
||||
.Fl P
|
||||
flags to determine what data will be sent.
|
||||
In this case, the verbose output will be written to
|
||||
standard output (contrast with a non-dry-run, where the stream is written
|
||||
to standard output and the verbose output goes to standard error).
|
||||
.It Fl P
|
||||
Print machine-parsable verbose information about the stream package generated.
|
||||
.It Fl v
|
||||
@ -2711,15 +2729,28 @@ feature.
|
||||
.El
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm send
|
||||
.Op Fl Penv
|
||||
.Fl t
|
||||
.Ar receive_resume_token
|
||||
.Xc
|
||||
Creates a send stream which resumes an interrupted receive. The
|
||||
.Ar receive_resume_token
|
||||
is the value of this property on the filesystem
|
||||
or volume that was being received into. See the documentation for
|
||||
.Sy zfs receive -s
|
||||
for more details.
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Op Fl vnFu
|
||||
.Op Fl vnsFu
|
||||
.Op Fl o Sy origin Ns = Ns Ar snapshot
|
||||
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot
|
||||
.Xc
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Op Fl vnFu
|
||||
.Op Fl vnsFu
|
||||
.Op Fl d | e
|
||||
.Op Fl o Sy origin Ns = Ns Ar snapshot
|
||||
.Ar filesystem
|
||||
@ -2816,9 +2847,42 @@ performing the receive operation. If receiving an incremental replication
|
||||
stream (for example, one generated by
|
||||
.Qq Nm Cm send Fl R Bro Fl i | Fl I Brc ) ,
|
||||
destroy snapshots and file systems that do not exist on the sending side.
|
||||
.It Fl s
|
||||
If the receive is interrupted, save the partially received state, rather
|
||||
than deleting it. Interruption may be due to premature termination of
|
||||
the stream
|
||||
.Po e.g. due to network failure or failure of the remote system
|
||||
if the stream is being read over a network connection
|
||||
.Pc ,
|
||||
a checksum error in the stream, termination of the
|
||||
.Nm zfs Cm receive
|
||||
process, or unclean shutdown of the system.
|
||||
.Pp
|
||||
The receive can be resumed with a stream generated by
|
||||
.Nm zfs Cm send Fl t Ar token ,
|
||||
where the
|
||||
.Ar token
|
||||
is the value of the
|
||||
.Sy receive_resume_token
|
||||
property of the filesystem or volume which is received into.
|
||||
.Pp
|
||||
To use this flag, the storage pool must have the
|
||||
.Sy extensible_dataset
|
||||
feature enabled. See
|
||||
.Xr zpool-features 5
|
||||
for details on ZFS feature flags.
|
||||
.El
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm receive Ns | Ns Cm recv
|
||||
.Fl A
|
||||
.Ar filesystem Ns | Ns Ar volume
|
||||
.Xc
|
||||
Abort an interrupted
|
||||
.Nm zfs Cm receive Fl s ,
|
||||
deleting its saved partially received state.
|
||||
.It Xo
|
||||
.Nm
|
||||
.Cm allow
|
||||
.Ar filesystem Ns | Ns Ar volume
|
||||
.Xc
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright 2012 Milan Jurik. All rights reserved.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
@ -263,10 +263,11 @@ get_usage(zfs_help_t idx)
|
||||
case HELP_PROMOTE:
|
||||
return (gettext("\tpromote <clone-filesystem>\n"));
|
||||
case HELP_RECEIVE:
|
||||
return (gettext("\treceive|recv [-vnFu] <filesystem|volume|"
|
||||
return (gettext("\treceive|recv [-vnsFu] <filesystem|volume|"
|
||||
"snapshot>\n"
|
||||
"\treceive|recv [-vnFu] [-o origin=<snapshot>] [-d | -e] "
|
||||
"<filesystem>\n"));
|
||||
"\treceive|recv [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
|
||||
"<filesystem>\n"
|
||||
"\treceive|recv -A <filesystem|volume>\n"));
|
||||
case HELP_RENAME:
|
||||
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
|
||||
"<filesystem|volume|snapshot>\n"
|
||||
@ -279,9 +280,10 @@ get_usage(zfs_help_t idx)
|
||||
return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
|
||||
"<snapshot>\n"
|
||||
"\tsend [-Le] [-i snapshot|bookmark] "
|
||||
"<filesystem|volume|snapshot>\n"));
|
||||
"<filesystem|volume|snapshot>\n"
|
||||
"\tsend [-nvPe] -t <receive_resume_token>\n"));
|
||||
case HELP_SET:
|
||||
return (gettext("\tset <property=value> "
|
||||
return (gettext("\tset <property=value> ... "
|
||||
"<filesystem|volume|snapshot> ...\n"));
|
||||
case HELP_SHARE:
|
||||
return (gettext("\tshare <-a | filesystem>\n"));
|
||||
@ -496,6 +498,10 @@ usage(boolean_t requested)
|
||||
exit(requested ? 0 : 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a property=value argument string and add it to the given nvlist.
|
||||
* Modifies the argument inplace.
|
||||
*/
|
||||
static int
|
||||
parseprop(nvlist_t *props, char *propname)
|
||||
{
|
||||
@ -503,7 +509,7 @@ parseprop(nvlist_t *props, char *propname)
|
||||
|
||||
if ((propval = strchr(propname, '=')) == NULL) {
|
||||
(void) fprintf(stderr, gettext("missing "
|
||||
"'=' for -o option\n"));
|
||||
"'=' for property=value argument\n"));
|
||||
return (-1);
|
||||
}
|
||||
*propval = '\0';
|
||||
@ -630,7 +636,7 @@ zfs_do_clone(int argc, char **argv)
|
||||
while ((c = getopt(argc, argv, "o:p")) != -1) {
|
||||
switch (c) {
|
||||
case 'o':
|
||||
if (parseprop(props, optarg))
|
||||
if (parseprop(props, optarg) != 0)
|
||||
return (1);
|
||||
break;
|
||||
case 'p':
|
||||
@ -839,10 +845,12 @@ zfs_do_create(int argc, char **argv)
|
||||
|
||||
if (type == ZFS_TYPE_VOLUME && !noreserve) {
|
||||
zpool_handle_t *zpool_handle;
|
||||
nvlist_t *real_props;
|
||||
uint64_t spa_version;
|
||||
char *p;
|
||||
zfs_prop_t resv_prop;
|
||||
char *strval;
|
||||
char msg[1024];
|
||||
|
||||
if (p = strchr(argv[0], '/'))
|
||||
*p = '\0';
|
||||
@ -853,12 +861,22 @@ zfs_do_create(int argc, char **argv)
|
||||
goto error;
|
||||
spa_version = zpool_get_prop_int(zpool_handle,
|
||||
ZPOOL_PROP_VERSION, NULL);
|
||||
zpool_close(zpool_handle);
|
||||
if (spa_version >= SPA_VERSION_REFRESERVATION)
|
||||
resv_prop = ZFS_PROP_REFRESERVATION;
|
||||
else
|
||||
resv_prop = ZFS_PROP_RESERVATION;
|
||||
volsize = zvol_volsize_to_reservation(volsize, props);
|
||||
|
||||
(void) snprintf(msg, sizeof (msg),
|
||||
gettext("cannot create '%s'"), argv[0]);
|
||||
if (props && (real_props = zfs_valid_proplist(g_zfs, type,
|
||||
props, 0, NULL, zpool_handle, msg)) == NULL) {
|
||||
zpool_close(zpool_handle);
|
||||
goto error;
|
||||
}
|
||||
zpool_close(zpool_handle);
|
||||
|
||||
volsize = zvol_volsize_to_reservation(volsize, real_props);
|
||||
nvlist_free(real_props);
|
||||
|
||||
if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
|
||||
&strval) != 0) {
|
||||
@ -3530,21 +3548,17 @@ zfs_do_rollback(int argc, char **argv)
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs set property=value { fs | snap | vol } ...
|
||||
* zfs set property=value ... { fs | snap | vol } ...
|
||||
*
|
||||
* Sets the given property for all datasets specified on the command line.
|
||||
* Sets the given properties for all datasets specified on the command line.
|
||||
*/
|
||||
typedef struct set_cbdata {
|
||||
char *cb_propname;
|
||||
char *cb_value;
|
||||
} set_cbdata_t;
|
||||
|
||||
static int
|
||||
set_callback(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
set_cbdata_t *cbp = data;
|
||||
nvlist_t *props = data;
|
||||
|
||||
if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) {
|
||||
if (zfs_prop_set_list(zhp, props) != 0) {
|
||||
switch (libzfs_errno(g_zfs)) {
|
||||
case EZFS_MOUNTFAILED:
|
||||
(void) fprintf(stderr, gettext("property may be set "
|
||||
@ -3563,7 +3577,8 @@ set_callback(zfs_handle_t *zhp, void *data)
|
||||
static int
|
||||
zfs_do_set(int argc, char **argv)
|
||||
{
|
||||
set_cbdata_t cb;
|
||||
nvlist_t *props = NULL;
|
||||
int ds_start = -1; /* argv idx of first dataset arg */
|
||||
int ret = 0;
|
||||
|
||||
/* check for options */
|
||||
@ -3575,36 +3590,51 @@ zfs_do_set(int argc, char **argv)
|
||||
|
||||
/* check number of arguments */
|
||||
if (argc < 2) {
|
||||
(void) fprintf(stderr, gettext("missing property=value "
|
||||
"argument\n"));
|
||||
(void) fprintf(stderr, gettext("missing arguments\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
if (argc < 3) {
|
||||
(void) fprintf(stderr, gettext("missing dataset name\n"));
|
||||
if (strchr(argv[1], '=') == NULL) {
|
||||
(void) fprintf(stderr, gettext("missing property=value "
|
||||
"argument(s)\n"));
|
||||
} else {
|
||||
(void) fprintf(stderr, gettext("missing dataset "
|
||||
"name(s)\n"));
|
||||
}
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
/* validate property=value argument */
|
||||
cb.cb_propname = argv[1];
|
||||
if (((cb.cb_value = strchr(cb.cb_propname, '=')) == NULL) ||
|
||||
(cb.cb_value[1] == '\0')) {
|
||||
(void) fprintf(stderr, gettext("missing value in "
|
||||
"property=value argument\n"));
|
||||
/* validate argument order: prop=val args followed by dataset args */
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strchr(argv[i], '=') != NULL) {
|
||||
if (ds_start > 0) {
|
||||
/* out-of-order prop=val argument */
|
||||
(void) fprintf(stderr, gettext("invalid "
|
||||
"argument order\n"), i);
|
||||
usage(B_FALSE);
|
||||
}
|
||||
} else if (ds_start < 0) {
|
||||
ds_start = i;
|
||||
}
|
||||
}
|
||||
if (ds_start < 0) {
|
||||
(void) fprintf(stderr, gettext("missing dataset name(s)\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
*cb.cb_value = '\0';
|
||||
cb.cb_value++;
|
||||
|
||||
if (*cb.cb_propname == '\0') {
|
||||
(void) fprintf(stderr,
|
||||
gettext("missing property in property=value argument\n"));
|
||||
usage(B_FALSE);
|
||||
/* Populate a list of property settings */
|
||||
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
||||
nomem();
|
||||
for (int i = 1; i < ds_start; i++) {
|
||||
if ((ret = parseprop(props, argv[i])) != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = zfs_for_each(argc - 2, argv + 2, 0,
|
||||
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
|
||||
ret = zfs_for_each(argc - ds_start, argv + ds_start, 0,
|
||||
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props);
|
||||
|
||||
error:
|
||||
nvlist_free(props);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -3728,6 +3758,7 @@ zfs_do_send(int argc, char **argv)
|
||||
{
|
||||
char *fromname = NULL;
|
||||
char *toname = NULL;
|
||||
char *resume_token = NULL;
|
||||
char *cp;
|
||||
zfs_handle_t *zhp;
|
||||
sendflags_t flags = { 0 };
|
||||
@ -3736,7 +3767,7 @@ zfs_do_send(int argc, char **argv)
|
||||
boolean_t extraverbose = B_FALSE;
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, ":i:I:RDpvnPLe")) != -1) {
|
||||
while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
if (fromname)
|
||||
@ -3777,6 +3808,9 @@ zfs_do_send(int argc, char **argv)
|
||||
case 'e':
|
||||
flags.embed_data = B_TRUE;
|
||||
break;
|
||||
case 't':
|
||||
resume_token = optarg;
|
||||
break;
|
||||
case ':':
|
||||
(void) fprintf(stderr, gettext("missing argument for "
|
||||
"'%c' option\n"), optopt);
|
||||
@ -3792,14 +3826,28 @@ zfs_do_send(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* check number of arguments */
|
||||
if (argc < 1) {
|
||||
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
if (argc > 1) {
|
||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||
usage(B_FALSE);
|
||||
if (resume_token != NULL) {
|
||||
if (fromname != NULL || flags.replicate || flags.props ||
|
||||
flags.dedup) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("invalid flags combined with -t\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
if (argc != 0) {
|
||||
(void) fprintf(stderr, gettext("no additional "
|
||||
"arguments are permitted with -t\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
} else {
|
||||
if (argc < 1) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("missing snapshot argument\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
if (argc > 1) {
|
||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.dryrun && isatty(STDOUT_FILENO)) {
|
||||
@ -3809,6 +3857,11 @@ zfs_do_send(int argc, char **argv)
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (resume_token != NULL) {
|
||||
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
|
||||
resume_token));
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case sending a filesystem, or from a bookmark.
|
||||
*/
|
||||
@ -3914,8 +3967,6 @@ zfs_do_send(int argc, char **argv)
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs receive [-vnFu] [-d | -e] <fs@snap>
|
||||
*
|
||||
* Restore a backup stream from stdin.
|
||||
*/
|
||||
static int
|
||||
@ -3923,6 +3974,8 @@ zfs_do_receive(int argc, char **argv)
|
||||
{
|
||||
int c, err;
|
||||
recvflags_t flags = { 0 };
|
||||
boolean_t abort_resumable = B_FALSE;
|
||||
|
||||
nvlist_t *props;
|
||||
nvpair_t *nvp = NULL;
|
||||
|
||||
@ -3930,7 +3983,7 @@ zfs_do_receive(int argc, char **argv)
|
||||
nomem();
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, ":o:denuvF")) != -1) {
|
||||
while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
|
||||
switch (c) {
|
||||
case 'o':
|
||||
if (parseprop(props, optarg) != 0)
|
||||
@ -3952,9 +4005,15 @@ zfs_do_receive(int argc, char **argv)
|
||||
case 'v':
|
||||
flags.verbose = B_TRUE;
|
||||
break;
|
||||
case 's':
|
||||
flags.resumable = B_TRUE;
|
||||
break;
|
||||
case 'F':
|
||||
flags.force = B_TRUE;
|
||||
break;
|
||||
case 'A':
|
||||
abort_resumable = B_TRUE;
|
||||
break;
|
||||
case ':':
|
||||
(void) fprintf(stderr, gettext("missing argument for "
|
||||
"'%c' option\n"), optopt);
|
||||
@ -3987,6 +4046,44 @@ zfs_do_receive(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (abort_resumable) {
|
||||
if (flags.isprefix || flags.istail || flags.dryrun ||
|
||||
flags.resumable || flags.nomount) {
|
||||
(void) fprintf(stderr, gettext("invalid option"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
char namebuf[ZFS_MAXNAMELEN];
|
||||
(void) snprintf(namebuf, sizeof (namebuf),
|
||||
"%s/%%recv", argv[0]);
|
||||
|
||||
if (zfs_dataset_exists(g_zfs, namebuf,
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
|
||||
zfs_handle_t *zhp = zfs_open(g_zfs,
|
||||
namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (zhp == NULL)
|
||||
return (1);
|
||||
err = zfs_destroy(zhp, B_FALSE);
|
||||
} else {
|
||||
zfs_handle_t *zhp = zfs_open(g_zfs,
|
||||
argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (zhp == NULL)
|
||||
usage(B_FALSE);
|
||||
if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
|
||||
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
|
||||
NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("'%s' does not have any "
|
||||
"resumable receive state to abort\n"),
|
||||
argv[0]);
|
||||
return (1);
|
||||
}
|
||||
err = zfs_destroy(zhp, B_FALSE);
|
||||
}
|
||||
|
||||
return (err != 0);
|
||||
}
|
||||
|
||||
if (isatty(STDIN_FILENO)) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("Error: Backup stream can not be read "
|
||||
@ -3994,7 +4091,6 @@ zfs_do_receive(int argc, char **argv)
|
||||
"You must redirect standard input.\n"));
|
||||
return (1);
|
||||
}
|
||||
|
||||
err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
|
||||
|
||||
return (err != 0);
|
||||
@ -5815,6 +5911,24 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this filesystem is inconsistent and has a receive resume
|
||||
* token, we can not mount it.
|
||||
*/
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
|
||||
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
|
||||
NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
|
||||
if (!explicit)
|
||||
return (0);
|
||||
|
||||
(void) fprintf(stderr, gettext("cannot %s '%s': "
|
||||
"Contains partially-completed state from "
|
||||
"\"zfs receive -r\", which can be resumed with "
|
||||
"\"zfs send -t\"\n"),
|
||||
cmdname, zfs_get_name(zhp));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have verified that the mountpoint and/or
|
||||
* shareopts are appropriate for auto management. If the
|
||||
|
@ -199,7 +199,8 @@ static boolean_t log_history = B_TRUE;
|
||||
static uint_t timestamp_fmt = NODATE;
|
||||
|
||||
static const char *
|
||||
get_usage(zpool_help_t idx) {
|
||||
get_usage(zpool_help_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case HELP_ADD:
|
||||
return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
|
||||
@ -2940,6 +2941,9 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
||||
uint_t c, children;
|
||||
char *vname;
|
||||
boolean_t scripted = cb->cb_scripted;
|
||||
uint64_t islog = B_FALSE;
|
||||
boolean_t haslog = B_FALSE;
|
||||
char *dashes = "%-*s - - - - - -\n";
|
||||
|
||||
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
|
||||
(uint64_t **)&vs, &c) == 0);
|
||||
@ -2990,24 +2994,47 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
||||
ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
|
||||
continue;
|
||||
|
||||
if (nvlist_lookup_uint64(child[c],
|
||||
ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
|
||||
haslog = B_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2);
|
||||
free(vname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Include level 2 ARC devices in iostat output
|
||||
*/
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
|
||||
&child, &children) != 0)
|
||||
return;
|
||||
|
||||
if (children > 0) {
|
||||
(void) printf("%-*s - - - - - "
|
||||
"-\n", cb->cb_namewidth, "cache");
|
||||
if (haslog == B_TRUE) {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth, "log");
|
||||
for (c = 0; c < children; c++) {
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||
B_FALSE);
|
||||
if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
|
||||
&islog) != 0 || !islog)
|
||||
continue;
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2);
|
||||
free(vname);
|
||||
}
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
|
||||
&child, &children) == 0 && children > 0) {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth, "cache");
|
||||
for (c = 0; c < children; c++) {
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2);
|
||||
free(vname);
|
||||
}
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
|
||||
&children) == 0 && children > 0) {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth, "spare");
|
||||
for (c = 0; c < children; c++) {
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2);
|
||||
free(vname);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
|
||||
saved_cksum.zc_word[1],
|
||||
saved_cksum.zc_word[2],
|
||||
saved_cksum.zc_word[3]);
|
||||
exit(1);
|
||||
return (0);
|
||||
}
|
||||
return (sizeof (*drr));
|
||||
}
|
||||
@ -346,8 +346,7 @@ main(int argc, char *argv[])
|
||||
if (verbose)
|
||||
(void) printf("\n");
|
||||
|
||||
if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
|
||||
DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
|
||||
if (drr->drr_payloadlen != 0) {
|
||||
nvlist_t *nv;
|
||||
int sz = drr->drr_payloadlen;
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright (c) 2013 Steven Hartland. All rights reserved.
|
||||
@ -426,10 +426,11 @@ extern const char *zfs_prop_column_name(zfs_prop_t);
|
||||
extern boolean_t zfs_prop_align_right(zfs_prop_t);
|
||||
|
||||
extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
|
||||
nvlist_t *, uint64_t, zfs_handle_t *, const char *);
|
||||
nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
|
||||
|
||||
extern const char *zfs_prop_to_name(zfs_prop_t);
|
||||
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
|
||||
extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
|
||||
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
|
||||
zprop_source_t *, char *, size_t, boolean_t);
|
||||
extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
|
||||
@ -621,6 +622,10 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
|
||||
extern int zfs_send(zfs_handle_t *, const char *, const char *,
|
||||
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
|
||||
extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
|
||||
extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
|
||||
const char *);
|
||||
extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
|
||||
const char *token);
|
||||
|
||||
extern int zfs_promote(zfs_handle_t *);
|
||||
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
|
||||
@ -661,6 +666,12 @@ typedef struct recvflags {
|
||||
/* set "canmount=off" on all modified filesystems */
|
||||
boolean_t canmountoff;
|
||||
|
||||
/*
|
||||
* Mark the file systems as "resumable" and do not destroy them if the
|
||||
* receive is interrupted
|
||||
*/
|
||||
boolean_t resumable;
|
||||
|
||||
/* byteswap flag is used internally; callers need not specify */
|
||||
boolean_t byteswap;
|
||||
|
||||
|
@ -74,6 +74,9 @@ zcmd_ioctl(int fd, int request, zfs_cmd_t *zc)
|
||||
|
||||
if (zfs_ioctl_version >= ZFS_IOCVER_DEADMAN) {
|
||||
switch (zfs_ioctl_version) {
|
||||
case ZFS_IOCVER_EDBP:
|
||||
cflag = ZFS_CMD_COMPAT_EDBP;
|
||||
break;
|
||||
case ZFS_IOCVER_ZCMD:
|
||||
cflag = ZFS_CMD_COMPAT_ZCMD;
|
||||
break;
|
||||
|
@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
@ -890,7 +890,8 @@ zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
|
||||
*/
|
||||
nvlist_t *
|
||||
zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
|
||||
uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
|
||||
uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
|
||||
const char *errbuf)
|
||||
{
|
||||
nvpair_t *elem;
|
||||
uint64_t intval;
|
||||
@ -1084,8 +1085,8 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
|
||||
case ZFS_PROP_RECORDSIZE:
|
||||
{
|
||||
int maxbs = SPA_MAXBLOCKSIZE;
|
||||
if (zhp != NULL) {
|
||||
maxbs = zpool_get_prop_int(zhp->zpool_hdl,
|
||||
if (zpool_hdl != NULL) {
|
||||
maxbs = zpool_get_prop_int(zpool_hdl,
|
||||
ZPOOL_PROP_MAXBLOCKSIZE, NULL);
|
||||
}
|
||||
/*
|
||||
@ -1403,6 +1404,7 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
|
||||
uint64_t old_reservation;
|
||||
uint64_t new_reservation;
|
||||
zfs_prop_t resv_prop;
|
||||
nvlist_t *props;
|
||||
|
||||
/*
|
||||
* If this is an existing volume, and someone is setting the volsize,
|
||||
@ -1412,16 +1414,25 @@ zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
|
||||
if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
|
||||
return (-1);
|
||||
old_reservation = zfs_prop_get_int(zhp, resv_prop);
|
||||
if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=
|
||||
old_reservation) || nvlist_lookup_uint64(nvl,
|
||||
zfs_prop_to_name(resv_prop), &new_reservation) != ENOENT) {
|
||||
|
||||
props = fnvlist_alloc();
|
||||
fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
|
||||
|
||||
if ((zvol_volsize_to_reservation(old_volsize, props) !=
|
||||
old_reservation) || nvlist_exists(nvl,
|
||||
zfs_prop_to_name(resv_prop))) {
|
||||
fnvlist_free(props);
|
||||
return (0);
|
||||
}
|
||||
if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
|
||||
&new_volsize) != 0)
|
||||
&new_volsize) != 0) {
|
||||
fnvlist_free(props);
|
||||
return (-1);
|
||||
new_reservation = zvol_volsize_to_reservation(new_volsize,
|
||||
zhp->zfs_props);
|
||||
}
|
||||
new_reservation = zvol_volsize_to_reservation(new_volsize, props);
|
||||
fnvlist_free(props);
|
||||
|
||||
if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
|
||||
new_reservation) != 0) {
|
||||
(void) no_memory(zhp->zfs_hdl);
|
||||
@ -1493,6 +1504,12 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
|
||||
"property setting is not allowed on "
|
||||
"bootable datasets"));
|
||||
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
|
||||
} else if (prop == ZFS_PROP_CHECKSUM ||
|
||||
prop == ZFS_PROP_DEDUP) {
|
||||
(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"property setting is not allowed on "
|
||||
"root pools"));
|
||||
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
|
||||
} else {
|
||||
(void) zfs_standard_error(hdl, err, errbuf);
|
||||
}
|
||||
@ -1528,15 +1545,10 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
|
||||
int
|
||||
zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = -1;
|
||||
prop_changelist_t *cl = NULL;
|
||||
char errbuf[1024];
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
nvlist_t *nvl = NULL, *realprops;
|
||||
zfs_prop_t prop;
|
||||
boolean_t do_prefix = B_TRUE;
|
||||
int added_resv;
|
||||
nvlist_t *nvl = NULL;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
|
||||
@ -1548,79 +1560,149 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl,
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
|
||||
goto error;
|
||||
ret = zfs_prop_set_list(zhp, nvl);
|
||||
|
||||
error:
|
||||
nvlist_free(nvl);
|
||||
nvl = realprops;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
prop = zfs_name_to_prop(propname);
|
||||
|
||||
/* We don't support those properties on FreeBSD. */
|
||||
switch (prop) {
|
||||
case ZFS_PROP_DEVICES:
|
||||
case ZFS_PROP_ISCSIOPTIONS:
|
||||
case ZFS_PROP_XATTR:
|
||||
case ZFS_PROP_VSCAN:
|
||||
case ZFS_PROP_NBMAND:
|
||||
case ZFS_PROP_MLSLABEL:
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
"property '%s' not supported on FreeBSD", propname);
|
||||
ret = zfs_error(hdl, EZFS_PERM, errbuf);
|
||||
|
||||
/*
|
||||
* Given an nvlist of property names and values, set the properties for the
|
||||
* given dataset.
|
||||
*/
|
||||
int
|
||||
zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
|
||||
{
|
||||
zfs_cmd_t zc = { 0 };
|
||||
int ret = -1;
|
||||
prop_changelist_t **cls = NULL;
|
||||
int cl_idx;
|
||||
char errbuf[1024];
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
nvlist_t *nvl;
|
||||
int nvl_len;
|
||||
int added_resv;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
|
||||
zhp->zfs_name);
|
||||
|
||||
if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
|
||||
zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
|
||||
errbuf)) == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (prop == ZFS_PROP_VOLSIZE) {
|
||||
if ((added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
|
||||
goto error;
|
||||
|
||||
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"child dataset with inherited mountpoint is used "
|
||||
"in a non-global zone"));
|
||||
ret = zfs_error(hdl, EZFS_ZONED, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want to unmount & remount the dataset when changing
|
||||
* its canmount property to 'on' or 'noauto'. We only use
|
||||
* the changelist logic to unmount when setting canmount=off.
|
||||
* We have to check for any extra properties which need to be added
|
||||
* before computing the length of the nvlist.
|
||||
*/
|
||||
if (prop == ZFS_PROP_CANMOUNT) {
|
||||
uint64_t idx;
|
||||
int err = zprop_string_to_index(prop, propval, &idx,
|
||||
ZFS_TYPE_DATASET);
|
||||
if (err == 0 && idx != ZFS_CANMOUNT_OFF)
|
||||
do_prefix = B_FALSE;
|
||||
for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem)) {
|
||||
if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
|
||||
(added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_prefix && (ret = changelist_prefix(cl)) != 0)
|
||||
/*
|
||||
* Check how many properties we're setting and allocate an array to
|
||||
* store changelist pointers for postfix().
|
||||
*/
|
||||
nvl_len = 0;
|
||||
for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem))
|
||||
nvl_len++;
|
||||
if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
|
||||
goto error;
|
||||
|
||||
cl_idx = 0;
|
||||
for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem)) {
|
||||
|
||||
zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
|
||||
|
||||
assert(cl_idx < nvl_len);
|
||||
/*
|
||||
* We don't want to unmount & remount the dataset when changing
|
||||
* its canmount property to 'on' or 'noauto'. We only use
|
||||
* the changelist logic to unmount when setting canmount=off.
|
||||
*/
|
||||
if (!(prop == ZFS_PROP_CANMOUNT &&
|
||||
fnvpair_value_uint64(elem) != ZFS_CANMOUNT_OFF)) {
|
||||
cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
|
||||
if (cls[cl_idx] == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (prop == ZFS_PROP_MOUNTPOINT &&
|
||||
changelist_haszonedchild(cls[cl_idx])) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"child dataset with inherited mountpoint is used "
|
||||
"in a non-global zone"));
|
||||
ret = zfs_error(hdl, EZFS_ZONED, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* We don't support those properties on FreeBSD. */
|
||||
switch (prop) {
|
||||
case ZFS_PROP_DEVICES:
|
||||
case ZFS_PROP_ISCSIOPTIONS:
|
||||
case ZFS_PROP_XATTR:
|
||||
case ZFS_PROP_VSCAN:
|
||||
case ZFS_PROP_NBMAND:
|
||||
case ZFS_PROP_MLSLABEL:
|
||||
(void) snprintf(errbuf, sizeof (errbuf),
|
||||
"property '%s' not supported on FreeBSD",
|
||||
nvpair_name(elem));
|
||||
ret = zfs_error(hdl, EZFS_PERM, errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (cls[cl_idx] != NULL &&
|
||||
(ret = changelist_prefix(cls[cl_idx])) != 0)
|
||||
goto error;
|
||||
|
||||
cl_idx++;
|
||||
}
|
||||
assert(cl_idx == nvl_len);
|
||||
|
||||
/*
|
||||
* Execute the corresponding ioctl() to set this property.
|
||||
* Execute the corresponding ioctl() to set this list of properties.
|
||||
*/
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
|
||||
if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
|
||||
(ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
|
||||
goto error;
|
||||
|
||||
ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
|
||||
|
||||
if (ret != 0) {
|
||||
zfs_setprop_error(hdl, prop, errno, errbuf);
|
||||
/* Get the list of unset properties back and report them. */
|
||||
nvlist_t *errorprops = NULL;
|
||||
if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
|
||||
goto error;
|
||||
for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
|
||||
elem != NULL;
|
||||
elem = nvlist_next_nvpair(nvl, elem)) {
|
||||
zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
|
||||
zfs_setprop_error(hdl, prop, errno, errbuf);
|
||||
}
|
||||
nvlist_free(errorprops);
|
||||
|
||||
if (added_resv && errno == ENOSPC) {
|
||||
/* clean up the volsize property we tried to set */
|
||||
uint64_t old_volsize = zfs_prop_get_int(zhp,
|
||||
ZFS_PROP_VOLSIZE);
|
||||
nvlist_free(nvl);
|
||||
nvl = NULL;
|
||||
zcmd_free_nvlists(&zc);
|
||||
|
||||
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
goto error;
|
||||
if (nvlist_add_uint64(nvl,
|
||||
@ -1632,8 +1714,13 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
||||
(void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
|
||||
}
|
||||
} else {
|
||||
if (do_prefix)
|
||||
ret = changelist_postfix(cl);
|
||||
for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
|
||||
if (cls[cl_idx] != NULL) {
|
||||
int clp_err = changelist_postfix(cls[cl_idx]);
|
||||
if (clp_err != 0)
|
||||
ret = clp_err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the statistics so the new property value
|
||||
@ -1646,8 +1733,13 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
|
||||
error:
|
||||
nvlist_free(nvl);
|
||||
zcmd_free_nvlists(&zc);
|
||||
if (cl)
|
||||
changelist_free(cl);
|
||||
if (cls != NULL) {
|
||||
for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
|
||||
if (cls[cl_idx] != NULL)
|
||||
changelist_free(cls[cl_idx]);
|
||||
}
|
||||
free(cls);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -1778,22 +1870,21 @@ getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
|
||||
return (value);
|
||||
}
|
||||
|
||||
static char *
|
||||
static const char *
|
||||
getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
|
||||
{
|
||||
nvlist_t *nv;
|
||||
char *value;
|
||||
const char *value;
|
||||
|
||||
*source = NULL;
|
||||
if (nvlist_lookup_nvlist(zhp->zfs_props,
|
||||
zfs_prop_to_name(prop), &nv) == 0) {
|
||||
verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
|
||||
value = fnvlist_lookup_string(nv, ZPROP_VALUE);
|
||||
(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
|
||||
} else {
|
||||
verify(!zhp->zfs_props_table ||
|
||||
zhp->zfs_props_table[prop] == B_TRUE);
|
||||
if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
|
||||
value = "";
|
||||
value = zfs_prop_default_string(prop);
|
||||
*source = "";
|
||||
}
|
||||
|
||||
@ -2195,7 +2286,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
{
|
||||
char *source = NULL;
|
||||
uint64_t val;
|
||||
char *str;
|
||||
const char *str;
|
||||
const char *strval;
|
||||
boolean_t received = zfs_is_recvd_props_mode(zhp);
|
||||
|
||||
@ -2300,14 +2391,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
break;
|
||||
|
||||
case ZFS_PROP_ORIGIN:
|
||||
(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
|
||||
proplen);
|
||||
/*
|
||||
* If there is no parent at all, return failure to indicate that
|
||||
* it doesn't apply to this dataset.
|
||||
*/
|
||||
if (propbuf[0] == '\0')
|
||||
str = getprop_string(zhp, prop, &source);
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
(void) strlcpy(propbuf, str, proplen);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_CLONES:
|
||||
@ -2488,8 +2575,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
break;
|
||||
|
||||
case PROP_TYPE_STRING:
|
||||
(void) strlcpy(propbuf,
|
||||
getprop_string(zhp, prop, &source), proplen);
|
||||
str = getprop_string(zhp, prop, &source);
|
||||
if (str == NULL)
|
||||
return (-1);
|
||||
(void) strlcpy(propbuf, str, proplen);
|
||||
break;
|
||||
|
||||
case PROP_TYPE_INDEX:
|
||||
@ -3167,9 +3256,23 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||
else
|
||||
ost = DMU_OST_ZFS;
|
||||
|
||||
/* open zpool handle for prop validation */
|
||||
char pool_path[MAXNAMELEN];
|
||||
(void) strlcpy(pool_path, path, sizeof (pool_path));
|
||||
|
||||
/* truncate pool_path at first slash */
|
||||
char *p = strchr(pool_path, '/');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
|
||||
zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path);
|
||||
|
||||
if (props && (props = zfs_valid_proplist(hdl, type, props,
|
||||
zoned, NULL, errbuf)) == 0)
|
||||
zoned, NULL, zpool_handle, errbuf)) == 0) {
|
||||
zpool_close(zpool_handle);
|
||||
return (-1);
|
||||
}
|
||||
zpool_close(zpool_handle);
|
||||
|
||||
if (type == ZFS_TYPE_VOLUME) {
|
||||
/*
|
||||
@ -3237,13 +3340,6 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
|
||||
"parent '%s' is not a filesystem"), parent);
|
||||
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
|
||||
|
||||
case EDOM:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"volume block size must be power of 2 from "
|
||||
"512B to 128KB"));
|
||||
|
||||
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
|
||||
|
||||
case ENOTSUP:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"pool must be upgraded to set this "
|
||||
@ -3438,7 +3534,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
|
||||
type = ZFS_TYPE_FILESYSTEM;
|
||||
}
|
||||
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
|
||||
zhp, errbuf)) == NULL)
|
||||
zhp, zhp->zpool_hdl, errbuf)) == NULL)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -3582,11 +3678,23 @@ zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get pool handle for prop validation. assumes all snaps are in the
|
||||
* same pool, as does lzc_snapshot (below).
|
||||
*/
|
||||
char pool[MAXNAMELEN];
|
||||
elem = nvlist_next_nvpair(snaps, NULL);
|
||||
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
|
||||
pool[strcspn(pool, "/@")] = '\0';
|
||||
zpool_handle_t *zpool_hdl = zpool_open(hdl, pool);
|
||||
|
||||
if (props != NULL &&
|
||||
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
|
||||
props, B_FALSE, NULL, errbuf)) == NULL) {
|
||||
props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
|
||||
zpool_close(zpool_hdl);
|
||||
return (-1);
|
||||
}
|
||||
zpool_close(zpool_hdl);
|
||||
|
||||
ret = lzc_snapshot(snaps, props, &errors);
|
||||
|
||||
@ -4200,7 +4308,7 @@ zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
|
||||
if (cmd == ZFS_SMB_ACL_RENAME) {
|
||||
if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
|
||||
(void) no_memory(hdl);
|
||||
return (NULL);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -624,9 +625,12 @@ get_snapshot_names(differ_info_t *di, const char *fromsnap,
|
||||
|
||||
zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
|
||||
while (zhp != NULL) {
|
||||
(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
|
||||
origin, sizeof (origin), &src, NULL, 0, B_FALSE);
|
||||
|
||||
if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
|
||||
sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
|
||||
(void) zfs_close(zhp);
|
||||
zhp = NULL;
|
||||
break;
|
||||
}
|
||||
if (strncmp(origin, fromsnap, fsnlen) == 0)
|
||||
break;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
|
||||
@ -315,7 +315,8 @@ typedef struct {
|
||||
} snapspec_arg_t;
|
||||
|
||||
static int
|
||||
snapspec_cb(zfs_handle_t *zhp, void *arg) {
|
||||
snapspec_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
snapspec_arg_t *ssa = arg;
|
||||
char *shortsnapname;
|
||||
int err = 0;
|
||||
|
@ -1072,6 +1072,17 @@ mount_cb(zfs_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this filesystem is inconsistent and has a receive resume
|
||||
* token, we can not mount it.
|
||||
*/
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
|
||||
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
|
||||
NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
libzfs_add_handle(cbp, zhp);
|
||||
if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
|
||||
zfs_close(zhp);
|
||||
|
@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -402,29 +402,6 @@ bootfs_name_valid(const char *pool, char *bootfs)
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect the configuration to determine if any of the devices contain
|
||||
* an EFI label.
|
||||
*/
|
||||
static boolean_t
|
||||
pool_uses_efi(nvlist_t *config)
|
||||
{
|
||||
#ifdef illumos
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
|
||||
if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0)
|
||||
return (read_efi_label(config, NULL) >= 0);
|
||||
|
||||
for (c = 0; c < children; c++) {
|
||||
if (pool_uses_efi(child[c]))
|
||||
return (B_TRUE);
|
||||
}
|
||||
#endif /* illumos */
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zpool_is_bootable(zpool_handle_t *zhp)
|
||||
{
|
||||
@ -453,7 +430,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
|
||||
char *slash, *check;
|
||||
struct stat64 statbuf;
|
||||
zpool_handle_t *zhp;
|
||||
nvlist_t *nvroot;
|
||||
|
||||
if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
|
||||
(void) no_memory(hdl);
|
||||
@ -572,23 +548,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
|
||||
(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
|
||||
goto error;
|
||||
}
|
||||
verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
|
||||
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
|
||||
|
||||
#ifdef illumos
|
||||
/*
|
||||
* bootfs property cannot be set on a disk which has
|
||||
* been EFI labeled.
|
||||
*/
|
||||
if (pool_uses_efi(nvroot)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"property '%s' not supported on "
|
||||
"EFI labeled devices"), propname);
|
||||
(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
|
||||
zpool_close(zhp);
|
||||
goto error;
|
||||
}
|
||||
#endif /* illumos */
|
||||
zpool_close(zhp);
|
||||
break;
|
||||
|
||||
@ -1164,8 +1123,8 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
|
||||
zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
|
||||
strcmp(zonestr, "on") == 0);
|
||||
|
||||
if ((zc_fsprops = zfs_valid_proplist(hdl,
|
||||
ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
|
||||
if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
|
||||
fsprops, zoned, NULL, NULL, msg)) == NULL) {
|
||||
goto create_failed;
|
||||
}
|
||||
if (!zc_props &&
|
||||
@ -1201,6 +1160,21 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
|
||||
"one or more vdevs refer to the same device"));
|
||||
return (zfs_error(hdl, EZFS_BADDEV, msg));
|
||||
|
||||
case ERANGE:
|
||||
/*
|
||||
* This happens if the record size is smaller or larger
|
||||
* than the allowed size range, or not a power of 2.
|
||||
*
|
||||
* NOTE: although zfs_valid_proplist is called earlier,
|
||||
* this case may have slipped through since the
|
||||
* pool does not exist yet and it is therefore
|
||||
* impossible to read properties e.g. max blocksize
|
||||
* from the pool.
|
||||
*/
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"record size invalid"));
|
||||
return (zfs_error(hdl, EZFS_BADPROP, msg));
|
||||
|
||||
case EOVERFLOW:
|
||||
/*
|
||||
* This occurs when one of the devices is below
|
||||
@ -1311,25 +1285,6 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
|
||||
return (zfs_error(hdl, EZFS_BADVERSION, msg));
|
||||
}
|
||||
|
||||
if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
|
||||
ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
|
||||
uint64_t s;
|
||||
|
||||
for (s = 0; s < nspares; s++) {
|
||||
char *path;
|
||||
|
||||
if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
|
||||
&path) == 0 && pool_uses_efi(spares[s])) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"device '%s' contains an EFI label and "
|
||||
"cannot be used on root pools."),
|
||||
zpool_vdev_name(hdl, NULL, spares[s],
|
||||
B_FALSE));
|
||||
return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
|
||||
SPA_VERSION_L2CACHE &&
|
||||
nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
|
||||
@ -1930,7 +1885,8 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func)
|
||||
* and the like.
|
||||
*/
|
||||
static int
|
||||
ctd_check_path(char *str) {
|
||||
ctd_check_path(char *str)
|
||||
{
|
||||
/*
|
||||
* If it starts with a slash, check the last component.
|
||||
*/
|
||||
@ -2350,11 +2306,9 @@ zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
|
||||
return (EZFS_INVALCONFIG);
|
||||
|
||||
/*
|
||||
* root pool can not have EFI labeled disks and can only have
|
||||
* a single top-level vdev.
|
||||
* root pool can only have a single top-level vdev.
|
||||
*/
|
||||
if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
|
||||
pool_uses_efi(vdev_root))
|
||||
if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
|
||||
return (EZFS_POOL_INVALARG);
|
||||
|
||||
(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
|
||||
@ -2658,16 +2612,6 @@ zpool_vdev_attach(zpool_handle_t *zhp,
|
||||
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
|
||||
"cannot attach %s to %s"), new_disk, old_disk);
|
||||
|
||||
/*
|
||||
* If this is a root pool, make sure that we're not attaching an
|
||||
* EFI labeled device.
|
||||
*/
|
||||
if (rootpool && pool_uses_efi(nvroot)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"EFI labeled devices are not supported on root pools."));
|
||||
return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
|
||||
}
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
|
||||
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
|
||||
&islog)) == 0)
|
||||
@ -3786,17 +3730,18 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
|
||||
int
|
||||
zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
uint64_t bufsize = HIS_BUF_LEN_DEF;
|
||||
char *buf;
|
||||
uint64_t buflen = HIS_BUF_LEN_DEF;
|
||||
uint64_t off = 0;
|
||||
nvlist_t **records = NULL;
|
||||
uint_t numrecords = 0;
|
||||
int err, i;
|
||||
|
||||
if ((buf = malloc(bufsize)) == NULL)
|
||||
buf = malloc(buflen);
|
||||
if (buf == NULL)
|
||||
return (ENOMEM);
|
||||
do {
|
||||
uint64_t bytes_read = bufsize;
|
||||
uint64_t bytes_read = buflen;
|
||||
uint64_t leftover;
|
||||
|
||||
if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
|
||||
@ -3810,18 +3755,16 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
|
||||
&leftover, &records, &numrecords)) != 0)
|
||||
break;
|
||||
off -= leftover;
|
||||
|
||||
/*
|
||||
* If the history block is too big, double the buffer
|
||||
* size and try again.
|
||||
*/
|
||||
if (leftover == bytes_read) {
|
||||
/*
|
||||
* no progress made, because buffer is not big enough
|
||||
* to hold this record; resize and retry.
|
||||
*/
|
||||
buflen *= 2;
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
bufsize <<= 1;
|
||||
if ((bufsize >= HIS_BUF_LEN_MAX) ||
|
||||
((buf = malloc(bufsize)) == NULL)) {
|
||||
if ((buflen >= HIS_BUF_LEN_MAX) ||
|
||||
((buf = malloc(buflen)) == NULL)) {
|
||||
err = ENOMEM;
|
||||
break;
|
||||
}
|
||||
@ -3829,6 +3772,7 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
|
||||
|
||||
/* CONSTCOND */
|
||||
} while (1);
|
||||
|
||||
free(buf);
|
||||
|
||||
if (!err) {
|
||||
@ -3981,13 +3925,6 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name)
|
||||
if (zhp) {
|
||||
nvlist_t *nvroot;
|
||||
|
||||
if (zpool_is_bootable(zhp)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"EFI labeled devices are not supported on root "
|
||||
"pools."));
|
||||
return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
|
||||
}
|
||||
|
||||
verify(nvlist_lookup_nvlist(zhp->zpool_config,
|
||||
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
@ -51,6 +51,7 @@
|
||||
#include "zfs_prop.h"
|
||||
#include "zfs_fletcher.h"
|
||||
#include "libzfs_impl.h"
|
||||
#include <zlib.h>
|
||||
#include <sha2.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/ddt.h>
|
||||
@ -67,6 +68,8 @@ extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
|
||||
static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
|
||||
recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
|
||||
uint64_t *);
|
||||
static int guid_to_name(libzfs_handle_t *, const char *,
|
||||
uint64_t, boolean_t, char *);
|
||||
|
||||
static const zio_cksum_t zero_cksum = { 0 };
|
||||
|
||||
@ -284,8 +287,7 @@ cksummer(void *arg)
|
||||
DMU_BACKUP_FEATURE_DEDUPPROPS);
|
||||
DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
|
||||
|
||||
if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
|
||||
DMU_COMPOUNDSTREAM && drr->drr_payloadlen != 0) {
|
||||
if (drr->drr_payloadlen != 0) {
|
||||
sz = drr->drr_payloadlen;
|
||||
|
||||
if (sz > SPA_MAXBLOCKSIZE) {
|
||||
@ -818,7 +820,8 @@ typedef struct send_dump_data {
|
||||
char prevsnap[ZFS_MAXNAMELEN];
|
||||
uint64_t prevsnap_obj;
|
||||
boolean_t seenfrom, seento, replicate, doall, fromorigin;
|
||||
boolean_t verbose, dryrun, parsable, progress, embed_data, large_block;
|
||||
boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
|
||||
boolean_t large_block;
|
||||
int outfd;
|
||||
boolean_t err;
|
||||
nvlist_t *fss;
|
||||
@ -994,17 +997,14 @@ static void *
|
||||
send_progress_thread(void *arg)
|
||||
{
|
||||
progress_arg_t *pa = arg;
|
||||
|
||||
zfs_cmd_t zc = { 0 };
|
||||
zfs_handle_t *zhp = pa->pa_zhp;
|
||||
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||
unsigned long long bytes;
|
||||
char buf[16];
|
||||
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
|
||||
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
if (!pa->pa_parsable)
|
||||
@ -1037,6 +1037,51 @@ send_progress_thread(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
|
||||
uint64_t size, boolean_t parsable)
|
||||
{
|
||||
if (parsable) {
|
||||
if (fromsnap != NULL) {
|
||||
(void) fprintf(fout, "incremental\t%s\t%s",
|
||||
fromsnap, tosnap);
|
||||
} else {
|
||||
(void) fprintf(fout, "full\t%s",
|
||||
tosnap);
|
||||
}
|
||||
} else {
|
||||
if (fromsnap != NULL) {
|
||||
if (strchr(fromsnap, '@') == NULL &&
|
||||
strchr(fromsnap, '#') == NULL) {
|
||||
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
|
||||
"send from @%s to %s"),
|
||||
fromsnap, tosnap);
|
||||
} else {
|
||||
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
|
||||
"send from %s to %s"),
|
||||
fromsnap, tosnap);
|
||||
}
|
||||
} else {
|
||||
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
|
||||
"full send of %s"),
|
||||
tosnap);
|
||||
}
|
||||
}
|
||||
|
||||
if (size != 0) {
|
||||
if (parsable) {
|
||||
(void) fprintf(fout, "\t%llu",
|
||||
(longlong_t)size);
|
||||
} else {
|
||||
char buf[16];
|
||||
zfs_nicenum(size, buf, sizeof (buf));
|
||||
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
|
||||
" estimated size is %s"), buf);
|
||||
}
|
||||
}
|
||||
(void) fprintf(fout, "\n");
|
||||
}
|
||||
|
||||
static int
|
||||
dump_snapshot(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
@ -1047,6 +1092,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
|
||||
int err;
|
||||
boolean_t isfromsnap, istosnap, fromorigin;
|
||||
boolean_t exclude = B_FALSE;
|
||||
FILE *fout = sdd->std_out ? stdout : stderr;
|
||||
|
||||
err = 0;
|
||||
thissnap = strchr(zhp->zfs_name, '@') + 1;
|
||||
@ -1115,37 +1161,14 @@ dump_snapshot(zfs_handle_t *zhp, void *arg)
|
||||
(sdd->fromorigin || sdd->replicate);
|
||||
|
||||
if (sdd->verbose) {
|
||||
uint64_t size;
|
||||
err = estimate_ioctl(zhp, sdd->prevsnap_obj,
|
||||
uint64_t size = 0;
|
||||
(void) estimate_ioctl(zhp, sdd->prevsnap_obj,
|
||||
fromorigin, &size);
|
||||
|
||||
if (sdd->parsable) {
|
||||
if (sdd->prevsnap[0] != '\0') {
|
||||
(void) fprintf(stderr, "incremental\t%s\t%s",
|
||||
sdd->prevsnap, zhp->zfs_name);
|
||||
} else {
|
||||
(void) fprintf(stderr, "full\t%s",
|
||||
zhp->zfs_name);
|
||||
}
|
||||
} else {
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
||||
"send from @%s to %s"),
|
||||
sdd->prevsnap, zhp->zfs_name);
|
||||
}
|
||||
if (err == 0) {
|
||||
if (sdd->parsable) {
|
||||
(void) fprintf(stderr, "\t%llu\n",
|
||||
(longlong_t)size);
|
||||
} else {
|
||||
char buf[16];
|
||||
zfs_nicenum(size, buf, sizeof (buf));
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
||||
" estimated size is %s\n"), buf);
|
||||
}
|
||||
sdd->size += size;
|
||||
} else {
|
||||
(void) fprintf(stderr, "\n");
|
||||
}
|
||||
send_print_verbose(fout, zhp->zfs_name,
|
||||
sdd->prevsnap[0] ? sdd->prevsnap : NULL,
|
||||
size, sdd->parsable);
|
||||
sdd->size += size;
|
||||
}
|
||||
|
||||
if (!sdd->dryrun) {
|
||||
@ -1356,6 +1379,233 @@ dump_filesystems(zfs_handle_t *rzhp, void *arg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
nvlist_t *
|
||||
zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
|
||||
{
|
||||
unsigned int version;
|
||||
int nread;
|
||||
unsigned long long checksum, packed_len;
|
||||
|
||||
/*
|
||||
* Decode token header, which is:
|
||||
* <token version>-<checksum of payload>-<uncompressed payload length>
|
||||
* Note that the only supported token version is 1.
|
||||
*/
|
||||
nread = sscanf(token, "%u-%llx-%llx-",
|
||||
&version, &checksum, &packed_len);
|
||||
if (nread != 3) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt (invalid format)"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt (invalid version %u)"),
|
||||
version);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* convert hexadecimal representation to binary */
|
||||
token = strrchr(token, '-') + 1;
|
||||
int len = strlen(token) / 2;
|
||||
unsigned char *compressed = zfs_alloc(hdl, len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
nread = sscanf(token + i * 2, "%2hhx", compressed + i);
|
||||
if (nread != 1) {
|
||||
free(compressed);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt "
|
||||
"(payload is not hex-encoded)"));
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* verify checksum */
|
||||
zio_cksum_t cksum;
|
||||
fletcher_4_native(compressed, len, NULL, &cksum);
|
||||
if (cksum.zc_word[0] != checksum) {
|
||||
free(compressed);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt (incorrect checksum)"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* uncompress */
|
||||
void *packed = zfs_alloc(hdl, packed_len);
|
||||
uLongf packed_len_long = packed_len;
|
||||
if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
|
||||
packed_len_long != packed_len) {
|
||||
free(packed);
|
||||
free(compressed);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt (decompression failed)"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* unpack nvlist */
|
||||
nvlist_t *nv;
|
||||
int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
|
||||
free(packed);
|
||||
free(compressed);
|
||||
if (error != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt (nvlist_unpack failed)"));
|
||||
return (NULL);
|
||||
}
|
||||
return (nv);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
|
||||
const char *resume_token)
|
||||
{
|
||||
char errbuf[1024];
|
||||
char *toname;
|
||||
char *fromname = NULL;
|
||||
uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;
|
||||
zfs_handle_t *zhp;
|
||||
int error = 0;
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
enum lzc_send_flags lzc_flags = 0;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot resume send"));
|
||||
|
||||
nvlist_t *resume_nvl =
|
||||
zfs_send_resume_token_to_nvlist(hdl, resume_token);
|
||||
if (resume_nvl == NULL) {
|
||||
/*
|
||||
* zfs_error_aux has already been set by
|
||||
* zfs_send_resume_token_to_nvlist
|
||||
*/
|
||||
return (zfs_error(hdl, EZFS_FAULT, errbuf));
|
||||
}
|
||||
if (flags->verbose) {
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
||||
"resume token contents:\n"));
|
||||
nvlist_print(stderr, resume_nvl);
|
||||
}
|
||||
|
||||
if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
|
||||
nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||
|
||||
nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||
|
||||
nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||
|
||||
nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"resume token is corrupt"));
|
||||
return (zfs_error(hdl, EZFS_FAULT, errbuf));
|
||||
}
|
||||
fromguid = 0;
|
||||
(void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
|
||||
|
||||
if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
|
||||
lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
|
||||
|
||||
if (guid_to_name(hdl, toname, toguid, B_FALSE, name) != 0) {
|
||||
if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"'%s' is no longer the same snapshot used in "
|
||||
"the initial send"), toname);
|
||||
} else {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"'%s' used in the initial send no longer exists"),
|
||||
toname);
|
||||
}
|
||||
return (zfs_error(hdl, EZFS_BADPATH, errbuf));
|
||||
}
|
||||
zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
|
||||
if (zhp == NULL) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"unable to access '%s'"), name);
|
||||
return (zfs_error(hdl, EZFS_BADPATH, errbuf));
|
||||
}
|
||||
|
||||
if (fromguid != 0) {
|
||||
if (guid_to_name(hdl, toname, fromguid, B_TRUE, name) != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"incremental source %#llx no longer exists"),
|
||||
(longlong_t)fromguid);
|
||||
return (zfs_error(hdl, EZFS_BADPATH, errbuf));
|
||||
}
|
||||
fromname = name;
|
||||
}
|
||||
|
||||
if (flags->verbose) {
|
||||
uint64_t size = 0;
|
||||
error = lzc_send_space(zhp->zfs_name, fromname, &size);
|
||||
if (error == 0)
|
||||
size = MAX(0, (int64_t)(size - bytes));
|
||||
send_print_verbose(stderr, zhp->zfs_name, fromname,
|
||||
size, flags->parsable);
|
||||
}
|
||||
|
||||
if (!flags->dryrun) {
|
||||
progress_arg_t pa = { 0 };
|
||||
pthread_t tid;
|
||||
/*
|
||||
* If progress reporting is requested, spawn a new thread to
|
||||
* poll ZFS_IOC_SEND_PROGRESS at a regular interval.
|
||||
*/
|
||||
if (flags->progress) {
|
||||
pa.pa_zhp = zhp;
|
||||
pa.pa_fd = outfd;
|
||||
pa.pa_parsable = flags->parsable;
|
||||
|
||||
error = pthread_create(&tid, NULL,
|
||||
send_progress_thread, &pa);
|
||||
if (error != 0) {
|
||||
zfs_close(zhp);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
error = lzc_send_resume(zhp->zfs_name, fromname, outfd,
|
||||
lzc_flags, resumeobj, resumeoff);
|
||||
|
||||
if (flags->progress) {
|
||||
(void) pthread_cancel(tid);
|
||||
(void) pthread_join(tid, NULL);
|
||||
}
|
||||
|
||||
char errbuf[1024];
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"warning: cannot send '%s'"), zhp->zfs_name);
|
||||
|
||||
zfs_close(zhp);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
return (0);
|
||||
case EXDEV:
|
||||
case ENOENT:
|
||||
case EDQUOT:
|
||||
case EFBIG:
|
||||
case EIO:
|
||||
case ENOLINK:
|
||||
case ENOSPC:
|
||||
#ifdef illumos
|
||||
case ENOSTR:
|
||||
#endif
|
||||
case ENXIO:
|
||||
case EPIPE:
|
||||
case ERANGE:
|
||||
case EFAULT:
|
||||
case EROFS:
|
||||
zfs_error_aux(hdl, strerror(errno));
|
||||
return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
|
||||
|
||||
default:
|
||||
return (zfs_standard_error(hdl, errno, errbuf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
zfs_close(zhp);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a send stream for the dataset identified by the argument zhp.
|
||||
*
|
||||
@ -1388,6 +1638,7 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
int pipefd[2];
|
||||
dedup_arg_t dda = { 0 };
|
||||
int featureflags = 0;
|
||||
FILE *fout;
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot send '%s'"), zhp->zfs_name);
|
||||
@ -1515,6 +1766,9 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
sdd.filter_cb_arg = cb_arg;
|
||||
if (debugnvp)
|
||||
sdd.debugnv = *debugnvp;
|
||||
if (sdd.verbose && sdd.dryrun)
|
||||
sdd.std_out = B_TRUE;
|
||||
fout = sdd.std_out ? stdout : stderr;
|
||||
|
||||
/*
|
||||
* Some flags require that we place user holds on the datasets that are
|
||||
@ -1554,12 +1808,12 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
|
||||
|
||||
if (flags->verbose) {
|
||||
if (flags->parsable) {
|
||||
(void) fprintf(stderr, "size\t%llu\n",
|
||||
(void) fprintf(fout, "size\t%llu\n",
|
||||
(longlong_t)sdd.size);
|
||||
} else {
|
||||
char buf[16];
|
||||
zfs_nicenum(sdd.size, buf, sizeof (buf));
|
||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
||||
(void) fprintf(fout, dgettext(TEXT_DOMAIN,
|
||||
"total estimated size is %s\n"), buf);
|
||||
}
|
||||
}
|
||||
@ -1891,6 +2145,7 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
|
||||
|
||||
typedef struct guid_to_name_data {
|
||||
uint64_t guid;
|
||||
boolean_t bookmark_ok;
|
||||
char *name;
|
||||
char *skip;
|
||||
} guid_to_name_data_t;
|
||||
@ -1899,20 +2154,25 @@ static int
|
||||
guid_to_name_cb(zfs_handle_t *zhp, void *arg)
|
||||
{
|
||||
guid_to_name_data_t *gtnd = arg;
|
||||
const char *slash;
|
||||
int err;
|
||||
|
||||
if (gtnd->skip != NULL &&
|
||||
strcmp(zhp->zfs_name, gtnd->skip) == 0) {
|
||||
(slash = strrchr(zhp->zfs_name, '/')) != NULL &&
|
||||
strcmp(slash + 1, gtnd->skip) == 0) {
|
||||
zfs_close(zhp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (zhp->zfs_dmustats.dds_guid == gtnd->guid) {
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid) {
|
||||
(void) strcpy(gtnd->name, zhp->zfs_name);
|
||||
zfs_close(zhp);
|
||||
return (EEXIST);
|
||||
}
|
||||
|
||||
err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
|
||||
if (err != EEXIST && gtnd->bookmark_ok)
|
||||
err = zfs_iter_bookmarks(zhp, guid_to_name_cb, gtnd);
|
||||
zfs_close(zhp);
|
||||
return (err);
|
||||
}
|
||||
@ -1926,45 +2186,48 @@ guid_to_name_cb(zfs_handle_t *zhp, void *arg)
|
||||
*/
|
||||
static int
|
||||
guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
|
||||
char *name)
|
||||
boolean_t bookmark_ok, char *name)
|
||||
{
|
||||
/* exhaustive search all local snapshots */
|
||||
char pname[ZFS_MAXNAMELEN];
|
||||
guid_to_name_data_t gtnd;
|
||||
int err = 0;
|
||||
zfs_handle_t *zhp;
|
||||
char *cp;
|
||||
|
||||
gtnd.guid = guid;
|
||||
gtnd.bookmark_ok = bookmark_ok;
|
||||
gtnd.name = name;
|
||||
gtnd.skip = NULL;
|
||||
|
||||
(void) strlcpy(pname, parent, sizeof (pname));
|
||||
|
||||
/*
|
||||
* Search progressively larger portions of the hierarchy. This will
|
||||
* Search progressively larger portions of the hierarchy, starting
|
||||
* with the filesystem specified by 'parent'. This will
|
||||
* select the "most local" version of the origin snapshot in the case
|
||||
* that there are multiple matching snapshots in the system.
|
||||
*/
|
||||
while ((cp = strrchr(pname, '/')) != NULL) {
|
||||
|
||||
(void) strlcpy(pname, parent, sizeof (pname));
|
||||
char *cp = strrchr(pname, '@');
|
||||
if (cp == NULL)
|
||||
cp = strchr(pname, '\0');
|
||||
for (; cp != NULL; cp = strrchr(pname, '/')) {
|
||||
/* Chop off the last component and open the parent */
|
||||
*cp = '\0';
|
||||
zhp = make_dataset_handle(hdl, pname);
|
||||
zfs_handle_t *zhp = make_dataset_handle(hdl, pname);
|
||||
|
||||
if (zhp == NULL)
|
||||
continue;
|
||||
|
||||
err = zfs_iter_children(zhp, guid_to_name_cb, >nd);
|
||||
int err = guid_to_name_cb(zfs_handle_dup(zhp), >nd);
|
||||
if (err != EEXIST)
|
||||
err = zfs_iter_children(zhp, guid_to_name_cb, >nd);
|
||||
if (err != EEXIST && bookmark_ok)
|
||||
err = zfs_iter_bookmarks(zhp, guid_to_name_cb, >nd);
|
||||
zfs_close(zhp);
|
||||
if (err == EEXIST)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Remember the dataset that we already searched, so we
|
||||
* skip it next time through.
|
||||
* Remember the last portion of the dataset so we skip it next
|
||||
* time through (as we've already searched that portion of the
|
||||
* hierarchy).
|
||||
*/
|
||||
gtnd.skip = pname;
|
||||
gtnd.skip = strrchr(pname, '/') + 1;
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
@ -2562,11 +2825,9 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
||||
|
||||
switch (drr->drr_type) {
|
||||
case DRR_BEGIN:
|
||||
/* NB: not to be used on v2 stream packages */
|
||||
if (drr->drr_payloadlen != 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid substream header"));
|
||||
return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
|
||||
(void) recv_read(hdl, fd, buf,
|
||||
drr->drr_payloadlen, B_FALSE, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2627,6 +2888,40 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
|
||||
boolean_t resumable)
|
||||
{
|
||||
char target_fs[ZFS_MAXNAMELEN];
|
||||
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"checksum mismatch or incomplete stream"));
|
||||
|
||||
if (!resumable)
|
||||
return;
|
||||
(void) strlcpy(target_fs, target_snap, sizeof (target_fs));
|
||||
*strchr(target_fs, '@') = '\0';
|
||||
zfs_handle_t *zhp = zfs_open(hdl, target_fs,
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
|
||||
if (zhp == NULL)
|
||||
return;
|
||||
|
||||
char token_buf[ZFS_MAXPROPLEN];
|
||||
int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
|
||||
token_buf, sizeof (token_buf),
|
||||
NULL, NULL, 0, B_TRUE);
|
||||
if (error == 0) {
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"checksum mismatch or incomplete stream.\n"
|
||||
"Partially received snapshot is saved.\n"
|
||||
"A resuming stream can be generated on the sending "
|
||||
"system by running:\n"
|
||||
" zfs send -t %s"),
|
||||
token_buf);
|
||||
}
|
||||
zfs_close(zhp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restores a backup of tosnap from the file descriptor specified by infd.
|
||||
*/
|
||||
@ -2790,7 +3085,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
*/
|
||||
if (drrb->drr_flags & DRR_FLAG_CLONE) {
|
||||
if (guid_to_name(hdl, zc.zc_value,
|
||||
drrb->drr_fromguid, zc.zc_string) != 0) {
|
||||
drrb->drr_fromguid, B_FALSE, zc.zc_string) != 0) {
|
||||
zcmd_free_nvlists(&zc);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"local origin for clone %s does not exist"),
|
||||
@ -2806,8 +3101,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
zc.zc_string);
|
||||
}
|
||||
|
||||
boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
|
||||
DMU_BACKUP_FEATURE_RESUMING;
|
||||
stream_wantsnewfs = (drrb->drr_fromguid == 0 ||
|
||||
(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap);
|
||||
(drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
|
||||
|
||||
if (stream_wantsnewfs) {
|
||||
/*
|
||||
@ -2826,7 +3123,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
char suffix[ZFS_MAXNAMELEN];
|
||||
(void) strcpy(suffix, strrchr(zc.zc_value, '/'));
|
||||
if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
|
||||
zc.zc_value) == 0) {
|
||||
B_FALSE, zc.zc_value) == 0) {
|
||||
*strchr(zc.zc_value, '@') = '\0';
|
||||
(void) strcat(zc.zc_value, suffix);
|
||||
}
|
||||
@ -2853,7 +3150,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
char snap[ZFS_MAXNAMELEN];
|
||||
(void) strcpy(snap, strchr(zc.zc_value, '@'));
|
||||
if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
|
||||
zc.zc_value) == 0) {
|
||||
B_FALSE, zc.zc_value) == 0) {
|
||||
*strchr(zc.zc_value, '@') = '\0';
|
||||
(void) strcat(zc.zc_value, snap);
|
||||
}
|
||||
@ -2867,11 +3164,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
zfs_handle_t *zhp;
|
||||
|
||||
/*
|
||||
* Destination fs exists. Therefore this should either
|
||||
* be an incremental, or the stream specifies a new fs
|
||||
* (full stream or clone) and they want us to blow it
|
||||
* away (and have therefore specified -F and removed any
|
||||
* snapshots).
|
||||
* Destination fs exists. It must be one of these cases:
|
||||
* - an incremental send stream
|
||||
* - the stream specifies a new fs (full stream or clone)
|
||||
* and they want us to blow away the existing fs (and
|
||||
* have therefore specified -F and removed any snapshots)
|
||||
* - we are resuming a failed receive.
|
||||
*/
|
||||
if (stream_wantsnewfs) {
|
||||
if (!flags->force) {
|
||||
@ -2926,6 +3224,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are resuming a newfs, set newfs here so that we will
|
||||
* mount it if the recv succeeds this time. We can tell
|
||||
* that it was a newfs on the first recv because the fs
|
||||
* itself will be inconsistent (if the fs existed when we
|
||||
* did the first recv, we would have received it into
|
||||
* .../%recv).
|
||||
*/
|
||||
if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
|
||||
newfs = B_TRUE;
|
||||
|
||||
zfs_close(zhp);
|
||||
} else {
|
||||
/*
|
||||
@ -2958,9 +3268,10 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
newfs = B_TRUE;
|
||||
}
|
||||
|
||||
zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
|
||||
zc.zc_begin_record = *drr_noswap;
|
||||
zc.zc_cookie = infd;
|
||||
zc.zc_guid = flags->force;
|
||||
zc.zc_resumable = flags->resumable;
|
||||
if (flags->verbose) {
|
||||
(void) printf("%s %s stream of %s into %s\n",
|
||||
flags->dryrun ? "would receive" : "receiving",
|
||||
@ -3097,8 +3408,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
||||
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
|
||||
break;
|
||||
case ECKSUM:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"invalid stream (checksum mismatch)"));
|
||||
recv_ecksum_set_aux(hdl, zc.zc_value, flags->resumable);
|
||||
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
|
||||
break;
|
||||
case ENOTSUP:
|
||||
@ -3300,7 +3610,8 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
|
||||
* Restores a backup of tosnap from the file descriptor specified by infd.
|
||||
* Return 0 on total success, -2 if some things couldn't be
|
||||
* destroyed/renamed/promoted, -1 if some things couldn't be received.
|
||||
* (-1 will override -2).
|
||||
* (-1 will override -2, if -1 and the resumable flag was specified the
|
||||
* transfer can be resumed if the sending side supports it).
|
||||
*/
|
||||
int
|
||||
zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
|
||||
|
@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -782,8 +782,9 @@ zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
|
||||
if (len == 0)
|
||||
len = 16 * 1024;
|
||||
zc->zc_nvlist_dst_size = len;
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
|
||||
zc->zc_nvlist_dst =
|
||||
(uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
|
||||
if (zc->zc_nvlist_dst == 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
@ -798,9 +799,9 @@ int
|
||||
zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
|
||||
{
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
|
||||
zfs_alloc(hdl, zc->zc_nvlist_dst_size))
|
||||
== 0)
|
||||
zc->zc_nvlist_dst =
|
||||
(uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
|
||||
if (zc->zc_nvlist_dst == 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
@ -815,6 +816,9 @@ zcmd_free_nvlists(zfs_cmd_t *zc)
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_conf);
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_src);
|
||||
free((void *)(uintptr_t)zc->zc_nvlist_dst);
|
||||
zc->zc_nvlist_conf = NULL;
|
||||
zc->zc_nvlist_src = NULL;
|
||||
zc->zc_nvlist_dst = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -514,6 +514,13 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp)
|
||||
int
|
||||
lzc_send(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags)
|
||||
{
|
||||
return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
|
||||
}
|
||||
|
||||
int
|
||||
lzc_send_resume(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
|
||||
{
|
||||
nvlist_t *args;
|
||||
int err;
|
||||
@ -526,6 +533,10 @@ lzc_send(const char *snapname, const char *from, int fd,
|
||||
fnvlist_add_boolean(args, "largeblockok");
|
||||
if (flags & LZC_SEND_FLAG_EMBED_DATA)
|
||||
fnvlist_add_boolean(args, "embedok");
|
||||
if (resumeobj != 0 || resumeoff != 0) {
|
||||
fnvlist_add_uint64(args, "resume_object", resumeobj);
|
||||
fnvlist_add_uint64(args, "resume_offset", resumeoff);
|
||||
}
|
||||
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
|
||||
nvlist_free(args);
|
||||
return (err);
|
||||
@ -583,22 +594,9 @@ recv_read(int fd, void *buf, int ilen)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The simplest receive case: receive from the specified fd, creating the
|
||||
* specified snapshot. Apply the specified properties a "received" properties
|
||||
* (which can be overridden by locally-set properties). If the stream is a
|
||||
* clone, its origin snapshot must be specified by 'origin'. The 'force'
|
||||
* flag will cause the target filesystem to be rolled back or destroyed if
|
||||
* necessary to receive.
|
||||
*
|
||||
* Return 0 on success or an errno on failure.
|
||||
*
|
||||
* Note: this interface does not work on dedup'd streams
|
||||
* (those with DMU_BACKUP_FEATURE_DEDUP).
|
||||
*/
|
||||
int
|
||||
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
static int
|
||||
lzc_receive_impl(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, boolean_t resumable, int fd)
|
||||
{
|
||||
/*
|
||||
* The receive ioctl is still legacy, so we need to construct our own
|
||||
@ -608,7 +606,6 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
char *atp;
|
||||
char *packed = NULL;
|
||||
size_t size;
|
||||
dmu_replay_record_t drr;
|
||||
int error;
|
||||
|
||||
ASSERT3S(g_refcount, >, 0);
|
||||
@ -644,10 +641,9 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string));
|
||||
|
||||
/* zc_begin_record is non-byteswapped BEGIN record */
|
||||
error = recv_read(fd, &drr, sizeof (drr));
|
||||
error = recv_read(fd, &zc.zc_begin_record, sizeof (zc.zc_begin_record));
|
||||
if (error != 0)
|
||||
goto out;
|
||||
zc.zc_begin_record = drr.drr_u.drr_begin;
|
||||
|
||||
/* zc_cookie is fd to read from */
|
||||
zc.zc_cookie = fd;
|
||||
@ -655,6 +651,8 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
/* zc guid is force flag */
|
||||
zc.zc_guid = force;
|
||||
|
||||
zc.zc_resumable = resumable;
|
||||
|
||||
/* zc_cleanup_fd is unused */
|
||||
zc.zc_cleanup_fd = -1;
|
||||
|
||||
@ -669,6 +667,39 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* The simplest receive case: receive from the specified fd, creating the
|
||||
* specified snapshot. Apply the specified properties as "received" properties
|
||||
* (which can be overridden by locally-set properties). If the stream is a
|
||||
* clone, its origin snapshot must be specified by 'origin'. The 'force'
|
||||
* flag will cause the target filesystem to be rolled back or destroyed if
|
||||
* necessary to receive.
|
||||
*
|
||||
* Return 0 on success or an errno on failure.
|
||||
*
|
||||
* Note: this interface does not work on dedup'd streams
|
||||
* (those with DMU_BACKUP_FEATURE_DEDUP).
|
||||
*/
|
||||
int
|
||||
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
{
|
||||
return (lzc_receive_impl(snapname, props, origin, force, B_FALSE, fd));
|
||||
}
|
||||
|
||||
/*
|
||||
* Like lzc_receive, but if the receive fails due to premature stream
|
||||
* termination, the intermediate state will be preserved on disk. In this
|
||||
* case, ECKSUM will be returned. The receive may subsequently be resumed
|
||||
* with a resuming send stream generated by lzc_send_resume().
|
||||
*/
|
||||
int
|
||||
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
|
||||
boolean_t force, int fd)
|
||||
{
|
||||
return (lzc_receive_impl(snapname, props, origin, force, B_TRUE, fd));
|
||||
}
|
||||
|
||||
/*
|
||||
* Roll back this filesystem or volume to its most recent snapshot.
|
||||
* If snapnamebuf is not NULL, it will be filled in with the name
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -59,7 +59,11 @@ enum lzc_send_flags {
|
||||
};
|
||||
|
||||
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
|
||||
int lzc_send_resume(const char *, const char *, int,
|
||||
enum lzc_send_flags, uint64_t, uint64_t);
|
||||
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
|
||||
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
|
||||
boolean_t, int);
|
||||
int lzc_send_space(const char *, const char *, uint64_t *);
|
||||
|
||||
boolean_t lzc_exists(const char *);
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
@ -523,7 +523,7 @@ vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
|
||||
int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
|
||||
int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
|
||||
{
|
||||
ssize_t iolen, split;
|
||||
|
||||
|
@ -8,10 +8,10 @@
|
||||
LIB= zfs
|
||||
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL} ${LIBM} ${LIBNVPAIR} \
|
||||
${LIBAVL} ${LIBZFS_CORE} ${LIBUUTIL} ${LIBBSDXML} ${LIBGEOM} \
|
||||
${LIBNVPAIR}
|
||||
${LIBNVPAIR} ${LIBZ}
|
||||
|
||||
LDADD= -lmd -lpthread -lumem -lutil -luutil -lm -lnvpair -lavl \
|
||||
-lbsdxml -lgeom -lnvpair -lzfs_core
|
||||
-lbsdxml -lgeom -lnvpair -lz -lzfs_core
|
||||
|
||||
SRCS= deviceid.c \
|
||||
fsshare.c \
|
||||
|
182
contrib/llvm/patches/patch-09-clang-r250657-openmp.diff
Normal file
182
contrib/llvm/patches/patch-09-clang-r250657-openmp.diff
Normal file
@ -0,0 +1,182 @@
|
||||
Pull in r248379 from upstream clang trunk (by Jörg Sonnenberger):
|
||||
|
||||
Refactor library decision for -fopenmp support from Darwin into a
|
||||
function for sharing with other platforms.
|
||||
|
||||
Pull in r248424 from upstream clang trunk (by Jörg Sonnenberger):
|
||||
|
||||
Push OpenMP linker flags after linker input on Darwin. Don't add any
|
||||
libraries if -nostdlib is specified. Test.
|
||||
|
||||
Pull in r248426 from upstream clang trunk (by Jörg Sonnenberger):
|
||||
|
||||
Support linking against OpenMP runtime on NetBSD.
|
||||
|
||||
Pull in r250657 from upstream clang trunk (by Dimitry Andric):
|
||||
|
||||
Support linking against OpenMP runtime on FreeBSD.
|
||||
|
||||
Introduced here: http://svnweb.freebsd.org/changeset/base/289523
|
||||
|
||||
Index: tools/clang/lib/Driver/Tools.cpp
|
||||
===================================================================
|
||||
--- tools/clang/lib/Driver/Tools.cpp
|
||||
+++ tools/clang/lib/Driver/Tools.cpp
|
||||
@@ -2460,6 +2460,28 @@ static OpenMPRuntimeKind getOpenMPRuntime(const To
|
||||
return RT;
|
||||
}
|
||||
|
||||
+static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
+ const ArgList &Args) {
|
||||
+ if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
+ options::OPT_fno_openmp, false))
|
||||
+ return;
|
||||
+
|
||||
+ switch (getOpenMPRuntime(TC, Args)) {
|
||||
+ case OMPRT_OMP:
|
||||
+ CmdArgs.push_back("-lomp");
|
||||
+ break;
|
||||
+ case OMPRT_GOMP:
|
||||
+ CmdArgs.push_back("-lgomp");
|
||||
+ break;
|
||||
+ case OMPRT_IOMP5:
|
||||
+ CmdArgs.push_back("-liomp5");
|
||||
+ break;
|
||||
+ case OMPRT_Unknown:
|
||||
+ // Already diagnosed.
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
|
||||
ArgStringList &CmdArgs, StringRef Sanitizer,
|
||||
bool IsShared) {
|
||||
@@ -6527,24 +6549,6 @@ void darwin::Linker::ConstructJob(Compilation &C,
|
||||
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
||||
|
||||
- if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
- options::OPT_fno_openmp, false)) {
|
||||
- switch (getOpenMPRuntime(getToolChain(), Args)) {
|
||||
- case OMPRT_OMP:
|
||||
- CmdArgs.push_back("-lomp");
|
||||
- break;
|
||||
- case OMPRT_GOMP:
|
||||
- CmdArgs.push_back("-lgomp");
|
||||
- break;
|
||||
- case OMPRT_IOMP5:
|
||||
- CmdArgs.push_back("-liomp5");
|
||||
- break;
|
||||
- case OMPRT_Unknown:
|
||||
- // Already diagnosed.
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
|
||||
// Build the input file for -filelist (list of linker input files) in case we
|
||||
// need it later
|
||||
@@ -6563,6 +6567,10 @@ void darwin::Linker::ConstructJob(Compilation &C,
|
||||
InputFileList.push_back(II.getFilename());
|
||||
}
|
||||
|
||||
+ if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
+ !Args.hasArg(options::OPT_nodefaultlibs))
|
||||
+ addOpenMPRuntime(CmdArgs, getToolChain(), Args);
|
||||
+
|
||||
if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
// We use arclite library for both ARC and subscripting support.
|
||||
@@ -7358,6 +7366,7 @@ void freebsd::Linker::ConstructJob(Compilation &C,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
+ addOpenMPRuntime(CmdArgs, ToolChain, Args);
|
||||
if (D.CCCIsCXX()) {
|
||||
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
if (Args.hasArg(options::OPT_pg))
|
||||
@@ -7673,6 +7682,7 @@ void netbsd::Linker::ConstructJob(Compilation &C,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
+ addOpenMPRuntime(CmdArgs, getToolChain(), Args);
|
||||
if (D.CCCIsCXX()) {
|
||||
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
CmdArgs.push_back("-lm");
|
||||
Index: tools/clang/test/Driver/fopenmp.c
|
||||
===================================================================
|
||||
--- tools/clang/test/Driver/fopenmp.c
|
||||
+++ tools/clang/test/Driver/fopenmp.c
|
||||
@@ -1,6 +1,15 @@
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-apple-darwin -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-apple-darwin -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP
|
||||
+// RUN: %clang -target x86_64-apple-darwin -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-freebsd -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-freebsd -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP
|
||||
+// RUN: %clang -target x86_64-freebsd -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP
|
||||
//
|
||||
// CHECK-CC1-OPENMP: "-cc1"
|
||||
// CHECK-CC1-OPENMP: "-fopenmp"
|
||||
@@ -12,6 +21,30 @@
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
|
||||
//
|
||||
+// RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
|
||||
+//
|
||||
+// RUN: %clang -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
|
||||
+// RUN: %clang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
|
||||
+// RUN: %clang -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
|
||||
+//
|
||||
+// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
|
||||
+//
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
|
||||
+//
|
||||
+// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
|
||||
+//
|
||||
+// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP
|
||||
+// RUN: %clang -nostdlib -target x86_64-netbsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5
|
||||
+//
|
||||
// CHECK-LD-OMP: "{{.*}}ld{{(.exe)?}}"
|
||||
// CHECK-LD-OMP: "-lomp"
|
||||
//
|
||||
@@ -21,6 +54,15 @@
|
||||
// CHECK-LD-IOMP5: "{{.*}}ld{{(.exe)?}}"
|
||||
// CHECK-LD-IOMP5: "-liomp5"
|
||||
//
|
||||
+// CHECK-NO-OMP: "{{.*}}ld{{(.exe)?}}"
|
||||
+// CHECK-NO-OMP-NOT: "-lomp"
|
||||
+//
|
||||
+// CHECK-NO-GOMP: "{{.*}}ld{{(.exe)?}}"
|
||||
+// CHECK-NO-GOMP-NOT: "-lgomp"
|
||||
+//
|
||||
+// CHECK-NO-IOMP5: "{{.*}}ld{{(.exe)?}}"
|
||||
+// CHECK-NO-IOMP5-NOT: "-liomp5"
|
||||
+//
|
||||
// We'd like to check that the default is sane, but until we have the ability
|
||||
// to *always* semantically analyze OpenMP without always generating runtime
|
||||
// calls (in the event of an unsupported runtime), we don't have a good way to
|
||||
@@ -28,6 +70,9 @@
|
||||
// OpenMP runtime.
|
||||
//
|
||||
// RUN: %clang -target x86_64-linux-gnu -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY
|
||||
+// RUN: %clang -target x86_64-darwin -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY
|
||||
+// RUN: %clang -target x86_64-freebsd -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY
|
||||
+// RUN: %clang -target x86_64-netbsd -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-ANY
|
||||
//
|
||||
// CHECK-LD-ANY: "{{.*}}ld{{(.exe)?}}"
|
||||
// CHECK-LD-ANY: "-l{{(omp|gomp|iomp5)}}"
|
@ -2460,6 +2460,28 @@ static OpenMPRuntimeKind getOpenMPRuntime(const ToolChain &TC,
|
||||
return RT;
|
||||
}
|
||||
|
||||
static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
const ArgList &Args) {
|
||||
if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
options::OPT_fno_openmp, false))
|
||||
return;
|
||||
|
||||
switch (getOpenMPRuntime(TC, Args)) {
|
||||
case OMPRT_OMP:
|
||||
CmdArgs.push_back("-lomp");
|
||||
break;
|
||||
case OMPRT_GOMP:
|
||||
CmdArgs.push_back("-lgomp");
|
||||
break;
|
||||
case OMPRT_IOMP5:
|
||||
CmdArgs.push_back("-liomp5");
|
||||
break;
|
||||
case OMPRT_Unknown:
|
||||
// Already diagnosed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
|
||||
ArgStringList &CmdArgs, StringRef Sanitizer,
|
||||
bool IsShared) {
|
||||
@ -6527,24 +6549,6 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
||||
|
||||
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
||||
options::OPT_fno_openmp, false)) {
|
||||
switch (getOpenMPRuntime(getToolChain(), Args)) {
|
||||
case OMPRT_OMP:
|
||||
CmdArgs.push_back("-lomp");
|
||||
break;
|
||||
case OMPRT_GOMP:
|
||||
CmdArgs.push_back("-lgomp");
|
||||
break;
|
||||
case OMPRT_IOMP5:
|
||||
CmdArgs.push_back("-liomp5");
|
||||
break;
|
||||
case OMPRT_Unknown:
|
||||
// Already diagnosed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
|
||||
// Build the input file for -filelist (list of linker input files) in case we
|
||||
// need it later
|
||||
@ -6563,6 +6567,10 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
InputFileList.push_back(II.getFilename());
|
||||
}
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs))
|
||||
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
|
||||
|
||||
if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
// We use arclite library for both ARC and subscripting support.
|
||||
@ -7358,6 +7366,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
addOpenMPRuntime(CmdArgs, ToolChain, Args);
|
||||
if (D.CCCIsCXX()) {
|
||||
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
if (Args.hasArg(options::OPT_pg))
|
||||
@ -7673,6 +7682,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
addOpenMPRuntime(CmdArgs, getToolChain(), Args);
|
||||
if (D.CCCIsCXX()) {
|
||||
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
CmdArgs.push_back("-lm");
|
||||
|
@ -44,6 +44,12 @@ length_head() {
|
||||
"the one expected to fail. (NetBSD PR bin/8521)"
|
||||
}
|
||||
length_body() {
|
||||
# Begin FreeBSD
|
||||
if ! df /dev/fd | grep -q '^fdescfs'; then
|
||||
atf_skip "fdescfs is not mounted on /dev/fd"
|
||||
fi
|
||||
# End FreeBSD
|
||||
|
||||
test_dd_length 512 \
|
||||
"dd if=/dev/zero of=/dev/fd/5 count=1 5>&1 >/dev/null 2>/dev/null"
|
||||
test_dd_length 512 \
|
||||
|
@ -481,7 +481,7 @@ kill \-HUP `cat @UNBOUND_PIDFILE@`
|
||||
.fi
|
||||
triggers a reload,
|
||||
.nf
|
||||
kill \-QUIT `cat @UNBOUND_PIDFILE@`
|
||||
kill \-TERM `cat @UNBOUND_PIDFILE@`
|
||||
.fi
|
||||
gracefully terminates.
|
||||
.TP
|
||||
|
@ -1,5 +1,41 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2015-09-27 - v2.5
|
||||
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
|
||||
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
|
||||
* fixed WMM Action frame parser
|
||||
[http://w1.fi/security/2015-3/] (CVE-2015-4142)
|
||||
* fixed EAP-pwd server missing payload length validation
|
||||
[http://w1.fi/security/2015-4/]
|
||||
(CVE-2015-4143, CVE-2015-4144, CVE-2015-4145)
|
||||
* fixed validation of WPS and P2P NFC NDEF record payload length
|
||||
[http://w1.fi/security/2015-5/]
|
||||
* nl80211:
|
||||
- fixed vendor command handling to check OUI properly
|
||||
* fixed hlr_auc_gw build with OpenSSL
|
||||
* hlr_auc_gw: allow Milenage RES length to be reduced
|
||||
* disable HT for a station that does not support WMM/QoS
|
||||
* added support for hashed password (NtHash) in EAP-pwd server
|
||||
* fixed and extended dynamic VLAN cases
|
||||
* added EAP-EKE server support for deriving Session-Id
|
||||
* set Acct-Session-Id to a random value to make it more likely to be
|
||||
unique even if the device does not have a proper clock
|
||||
* added more 2.4 GHz channels for 20/40 MHz HT co-ex scan
|
||||
* modified SAE routines to be more robust and PWE generation to be
|
||||
stronger against timing attacks
|
||||
* added support for Brainpool Elliptic Curves with SAE
|
||||
* increases maximum value accepted for cwmin/cwmax
|
||||
* added support for CCMP-256 and GCMP-256 as group ciphers with FT
|
||||
* added Fast Session Transfer (FST) module
|
||||
* removed optional fields from RSNE when using FT with PMF
|
||||
(workaround for interoperability issues with iOS 8.4)
|
||||
* added EAP server support for TLS session resumption
|
||||
* fixed key derivation for Suite B 192-bit AKM (this breaks
|
||||
compatibility with the earlier version)
|
||||
* added mechanism to track unconnected stations and do minimal band
|
||||
steering
|
||||
* number of small fixes
|
||||
|
||||
2015-03-15 - v2.4
|
||||
* allow OpenSSL cipher configuration to be set for internal EAP server
|
||||
(openssl_ciphers parameter)
|
||||
|
@ -222,9 +222,15 @@ static int hostapd_config_read_eap_user(const char *fname,
|
||||
return 0;
|
||||
|
||||
if (os_strncmp(fname, "sqlite:", 7) == 0) {
|
||||
#ifdef CONFIG_SQLITE
|
||||
os_free(conf->eap_user_sqlite);
|
||||
conf->eap_user_sqlite = os_strdup(fname + 7);
|
||||
return 0;
|
||||
#else /* CONFIG_SQLITE */
|
||||
wpa_printf(MSG_ERROR,
|
||||
"EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
|
||||
return -1;
|
||||
#endif /* CONFIG_SQLITE */
|
||||
}
|
||||
|
||||
f = fopen(fname, "r");
|
||||
@ -775,6 +781,24 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
|
||||
{
|
||||
char *pos;
|
||||
|
||||
/* for backwards compatibility, translate ' ' in conf str to ',' */
|
||||
pos = val;
|
||||
while (pos) {
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
*pos++ = ',';
|
||||
}
|
||||
if (freq_range_list_parse(&conf->acs_ch_list, val))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_parse_intlist(int **int_list, char *val)
|
||||
{
|
||||
int *list;
|
||||
@ -875,7 +899,9 @@ static int hostapd_config_read_int10(const char *value)
|
||||
static int valid_cw(int cw)
|
||||
{
|
||||
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
|
||||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
|
||||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
|
||||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
|
||||
cw == 32767);
|
||||
}
|
||||
|
||||
|
||||
@ -886,11 +912,11 @@ enum {
|
||||
IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
|
||||
};
|
||||
|
||||
static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
|
||||
char *val)
|
||||
static int hostapd_config_tx_queue(struct hostapd_config *conf,
|
||||
const char *name, const char *val)
|
||||
{
|
||||
int num;
|
||||
char *pos;
|
||||
const char *pos;
|
||||
struct hostapd_tx_queue_params *queue;
|
||||
|
||||
/* skip 'tx_queue_' prefix */
|
||||
@ -1134,13 +1160,23 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
|
||||
if (os_strstr(capab, "[BF-ANTENNA-2]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
|
||||
conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
|
||||
if (os_strstr(capab, "[BF-ANTENNA-3]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
|
||||
conf->vht_capab |= (2 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
|
||||
if (os_strstr(capab, "[BF-ANTENNA-4]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
|
||||
conf->vht_capab |= (3 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
|
||||
if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
|
||||
conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
|
||||
if (os_strstr(capab, "[SOUNDING-DIMENSION-3]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
|
||||
conf->vht_capab |= (2 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
|
||||
if (os_strstr(capab, "[SOUNDING-DIMENSION-4]") &&
|
||||
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
|
||||
conf->vht_capab |= (3 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
|
||||
if (os_strstr(capab, "[MU-BEAMFORMER]"))
|
||||
conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
|
||||
if (os_strstr(capab, "[MU-BEAMFORMEE]"))
|
||||
conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
if (os_strstr(capab, "[VHT-TXOP-PS]"))
|
||||
conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
|
||||
if (os_strstr(capab, "[HTC-VHT]"))
|
||||
@ -1699,7 +1735,7 @@ static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
|
||||
char *str;
|
||||
|
||||
str = wpa_config_parse_string(pos, &slen);
|
||||
if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
|
||||
if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
|
||||
os_free(str);
|
||||
return -1;
|
||||
@ -1900,7 +1936,7 @@ static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
|
||||
|
||||
static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss,
|
||||
char *buf, char *pos, int line)
|
||||
const char *buf, char *pos, int line)
|
||||
{
|
||||
if (os_strcmp(buf, "interface") == 0) {
|
||||
os_strlcpy(conf->bss[0]->iface, pos,
|
||||
@ -1946,7 +1982,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line);
|
||||
} else if (os_strcmp(buf, "ssid") == 0) {
|
||||
bss->ssid.ssid_len = os_strlen(pos);
|
||||
if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
|
||||
if (bss->ssid.ssid_len > SSID_MAX_LEN ||
|
||||
bss->ssid.ssid_len < 1) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
|
||||
line, pos);
|
||||
@ -1957,7 +1993,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} 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) {
|
||||
if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
|
||||
line, pos);
|
||||
os_free(str);
|
||||
@ -2043,6 +2079,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
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, "tls_session_lifetime") == 0) {
|
||||
bss->tls_session_lifetime = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
|
||||
os_free(bss->ocsp_stapling_response);
|
||||
bss->ocsp_stapling_response = os_strdup(pos);
|
||||
@ -2515,13 +2553,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
||||
else if (os_strcmp(pos, "ad") == 0)
|
||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
|
||||
else if (os_strcmp(pos, "any") == 0)
|
||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
|
||||
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)
|
||||
if (os_strcmp(pos, "ad") == 0)
|
||||
bss->wps_rf_bands = WPS_RF_60GHZ;
|
||||
else 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)
|
||||
@ -2542,12 +2584,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line);
|
||||
return 1;
|
||||
#else /* CONFIG_ACS */
|
||||
conf->acs = 1;
|
||||
conf->channel = 0;
|
||||
#endif /* CONFIG_ACS */
|
||||
} else
|
||||
} else {
|
||||
conf->channel = atoi(pos);
|
||||
conf->acs = conf->channel == 0;
|
||||
}
|
||||
} else if (os_strcmp(buf, "chanlist") == 0) {
|
||||
if (hostapd_parse_intlist(&conf->chanlist, pos)) {
|
||||
if (hostapd_parse_chanlist(conf, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
|
||||
line);
|
||||
return 1;
|
||||
@ -2810,7 +2855,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
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) {
|
||||
if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Too long "
|
||||
"device_name", line);
|
||||
return 1;
|
||||
@ -3111,6 +3156,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->disable_dgaf = atoi(pos);
|
||||
} else if (os_strcmp(buf, "proxy_arp") == 0) {
|
||||
bss->proxy_arp = atoi(pos);
|
||||
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
|
||||
bss->na_mcast_to_ucast = atoi(pos);
|
||||
} else if (os_strcmp(buf, "osen") == 0) {
|
||||
bss->osen = atoi(pos);
|
||||
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
|
||||
@ -3223,6 +3270,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->bss_load_test_set = 1;
|
||||
} else if (os_strcmp(buf, "radio_measurements") == 0) {
|
||||
bss->radio_measurements = atoi(pos);
|
||||
} else if (os_strcmp(buf, "own_ie_override") == 0) {
|
||||
struct wpabuf *tmp;
|
||||
size_t len = os_strlen(pos) / 2;
|
||||
|
||||
tmp = wpabuf_alloc(len);
|
||||
if (!tmp)
|
||||
return 1;
|
||||
|
||||
if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
|
||||
wpabuf_free(tmp);
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid own_ie_override '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wpabuf_free(bss->own_ie_override);
|
||||
bss->own_ie_override = tmp;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
} else if (os_strcmp(buf, "vendor_elements") == 0) {
|
||||
struct wpabuf *elems;
|
||||
@ -3276,6 +3341,74 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "wowlan_triggers") == 0) {
|
||||
os_free(bss->wowlan_triggers);
|
||||
bss->wowlan_triggers = os_strdup(pos);
|
||||
#ifdef CONFIG_FST
|
||||
} else if (os_strcmp(buf, "fst_group_id") == 0) {
|
||||
size_t len = os_strlen(pos);
|
||||
|
||||
if (!len || len >= sizeof(conf->fst_cfg.group_id)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid fst_group_id value '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (conf->fst_cfg.group_id[0]) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Duplicate fst_group value '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
os_strlcpy(conf->fst_cfg.group_id, pos,
|
||||
sizeof(conf->fst_cfg.group_id));
|
||||
} else if (os_strcmp(buf, "fst_priority") == 0) {
|
||||
char *endp;
|
||||
long int val;
|
||||
|
||||
if (!*pos) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: fst_priority value not supplied (expected 1..%u)",
|
||||
line, FST_MAX_PRIO_VALUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
val = strtol(pos, &endp, 0);
|
||||
if (*endp || val < 1 || val > FST_MAX_PRIO_VALUE) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid fst_priority %ld (%s) (expected 1..%u)",
|
||||
line, val, pos, FST_MAX_PRIO_VALUE);
|
||||
return 1;
|
||||
}
|
||||
conf->fst_cfg.priority = (u8) val;
|
||||
} else if (os_strcmp(buf, "fst_llt") == 0) {
|
||||
char *endp;
|
||||
long int val;
|
||||
|
||||
if (!*pos) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: fst_llt value not supplied (expected 1..%u)",
|
||||
line, FST_MAX_LLT_MS);
|
||||
return -1;
|
||||
}
|
||||
val = strtol(pos, &endp, 0);
|
||||
if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
|
||||
line, val, pos, FST_MAX_LLT_MS);
|
||||
return 1;
|
||||
}
|
||||
conf->fst_cfg.llt = (u32) val;
|
||||
#endif /* CONFIG_FST */
|
||||
} else if (os_strcmp(buf, "track_sta_max_num") == 0) {
|
||||
conf->track_sta_max_num = atoi(pos);
|
||||
} else if (os_strcmp(buf, "track_sta_max_age") == 0) {
|
||||
conf->track_sta_max_age = atoi(pos);
|
||||
} else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
|
||||
os_free(bss->no_probe_resp_if_seen_on);
|
||||
bss->no_probe_resp_if_seen_on = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
|
||||
os_free(bss->no_auth_if_seen_on);
|
||||
bss->no_auth_if_seen_on = os_strdup(pos);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
@ -3378,7 +3511,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
|
||||
|
||||
int hostapd_set_iface(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss, char *field, char *value)
|
||||
struct hostapd_bss_config *bss, const char *field,
|
||||
char *value)
|
||||
{
|
||||
int errors;
|
||||
size_t i;
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
int hostapd_set_iface(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss, char *field,
|
||||
struct hostapd_bss_config *bss, const char *field,
|
||||
char *value);
|
||||
|
||||
#endif /* CONFIG_FILE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -240,6 +240,12 @@ CONFIG_IPV6=y
|
||||
# requirements described above.
|
||||
#CONFIG_NO_RANDOM_POOL=y
|
||||
|
||||
# Should we use poll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_POLL=y
|
||||
|
||||
# Should we use epoll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_EPOLL=y
|
||||
|
||||
# Select TLS implementation
|
||||
# openssl = OpenSSL (default)
|
||||
# gnutls = GnuTLS
|
||||
@ -283,6 +289,12 @@ CONFIG_IPV6=y
|
||||
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
|
||||
#CONFIG_SQLITE=y
|
||||
|
||||
# Enable Fast Session Transfer (FST)
|
||||
#CONFIG_FST=y
|
||||
|
||||
# Enable CLI commands for FST testing
|
||||
#CONFIG_FST_TEST=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
|
||||
|
@ -87,6 +87,7 @@ struct milenage_parameters {
|
||||
u8 amf[2];
|
||||
u8 sqn[6];
|
||||
int set;
|
||||
size_t res_len;
|
||||
};
|
||||
|
||||
static struct milenage_parameters *milenage_db = NULL;
|
||||
@ -96,6 +97,7 @@ static struct milenage_parameters *milenage_db = NULL;
|
||||
#define EAP_AKA_RAND_LEN 16
|
||||
#define EAP_AKA_AUTN_LEN 16
|
||||
#define EAP_AKA_AUTS_LEN 14
|
||||
#define EAP_AKA_RES_MIN_LEN 4
|
||||
#define EAP_AKA_RES_MAX_LEN 16
|
||||
#define EAP_AKA_IK_LEN 16
|
||||
#define EAP_AKA_CK_LEN 16
|
||||
@ -124,7 +126,8 @@ static int db_table_create_milenage(sqlite3 *db)
|
||||
" ki CHAR(32) NOT NULL,"
|
||||
" opc CHAR(32) NOT NULL,"
|
||||
" amf CHAR(4) NOT NULL,"
|
||||
" sqn CHAR(12) NOT NULL"
|
||||
" sqn CHAR(12) NOT NULL,"
|
||||
" res_len INTEGER"
|
||||
");";
|
||||
|
||||
printf("Adding database table for milenage information\n");
|
||||
@ -190,6 +193,10 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
|
||||
printf("Invalid sqn value in database\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
|
||||
m->res_len = atoi(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -206,8 +213,7 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
|
||||
os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
|
||||
"%llu", imsi);
|
||||
os_snprintf(cmd, sizeof(cmd),
|
||||
"SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
|
||||
imsi);
|
||||
"SELECT * FROM milenage WHERE imsi=%llu;", imsi);
|
||||
if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
|
||||
NULL) != SQLITE_OK)
|
||||
return NULL;
|
||||
@ -424,7 +430,7 @@ static int read_milenage(const char *fname)
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
line++;
|
||||
|
||||
/* Parse IMSI Ki OPc AMF SQN */
|
||||
/* Parse IMSI Ki OPc AMF SQN [RES_len] */
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
@ -515,7 +521,19 @@ static int read_milenage(const char *fname)
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
if (pos2) {
|
||||
pos = pos2 + 1;
|
||||
m->res_len = atoi(pos);
|
||||
if (m->res_len &&
|
||||
(m->res_len < EAP_AKA_RES_MIN_LEN ||
|
||||
m->res_len > EAP_AKA_RES_MAX_LEN)) {
|
||||
printf("%s:%d - Invalid RES_len (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m->next = milenage_db;
|
||||
milenage_db = m;
|
||||
@ -532,7 +550,7 @@ static int read_milenage(const char *fname)
|
||||
static void update_milenage_file(const char *fname)
|
||||
{
|
||||
FILE *f, *f2;
|
||||
char buf[500], *pos;
|
||||
char name[500], buf[500], *pos;
|
||||
char *end = buf + sizeof(buf);
|
||||
struct milenage_parameters *m;
|
||||
size_t imsi_len;
|
||||
@ -543,10 +561,10 @@ static void update_milenage_file(const char *fname)
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s.new", fname);
|
||||
f2 = fopen(buf, "w");
|
||||
snprintf(name, sizeof(name), "%s.new", fname);
|
||||
f2 = fopen(name, "w");
|
||||
if (f2 == NULL) {
|
||||
printf("Could not write Milenage data file '%s'\n", buf);
|
||||
printf("Could not write Milenage data file '%s'\n", name);
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
@ -588,14 +606,14 @@ static void update_milenage_file(const char *fname)
|
||||
fclose(f2);
|
||||
fclose(f);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s.bak", fname);
|
||||
if (rename(fname, buf) < 0) {
|
||||
snprintf(name, sizeof(name), "%s.bak", fname);
|
||||
if (rename(fname, name) < 0) {
|
||||
perror("rename");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s.new", fname);
|
||||
if (rename(buf, fname) < 0) {
|
||||
snprintf(name, sizeof(name), "%s.new", fname);
|
||||
if (rename(name, fname) < 0) {
|
||||
perror("rename");
|
||||
return;
|
||||
}
|
||||
@ -798,6 +816,10 @@ static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
|
||||
}
|
||||
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
|
||||
autn, ik, ck, res, &res_len);
|
||||
if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
|
||||
m->res_len <= EAP_AKA_RES_MAX_LEN &&
|
||||
m->res_len < res_len)
|
||||
res_len = m->res_len;
|
||||
} else {
|
||||
printf("Unknown IMSI: %s\n", imsi);
|
||||
#ifdef AKA_USE_FIXED_TEST_VALUES
|
||||
|
@ -5,8 +5,10 @@
|
||||
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
|
||||
# dummy values will need to be included in this file.
|
||||
|
||||
# IMSI Ki OPc AMF SQN
|
||||
# IMSI Ki OPc AMF SQN [RES_len]
|
||||
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
|
||||
# Example using truncated 32-bit RES instead of 64-bit default
|
||||
232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
|
||||
|
||||
# These values are from Test Set 19 which has the AMF separation bit set to 1
|
||||
# and as such, is suitable for EAP-AKA' test.
|
||||
|
@ -127,7 +127,9 @@ ssid=test
|
||||
|
||||
# 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)
|
||||
# specify band). When using ACS (see channel parameter), a special value "any"
|
||||
# can be used to indicate that any support band can be used. This special case
|
||||
# is currently supported only with drivers with which offloaded ACS is used.
|
||||
# Default: IEEE 802.11b
|
||||
hw_mode=g
|
||||
|
||||
@ -170,8 +172,11 @@ channel=1
|
||||
|
||||
# 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)
|
||||
# Channel list can be provided as range using hyphen ('-') or individual
|
||||
# channels can be specified by space (' ') seperated values
|
||||
# Default: all channels allowed in selected hw_mode
|
||||
#chanlist=100 104 108 112 116
|
||||
#chanlist=1 6 11-13
|
||||
|
||||
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||
beacon_int=100
|
||||
@ -275,8 +280,9 @@ ignore_broadcast_ssid=0
|
||||
# (data0 is the highest priority queue)
|
||||
# parameters:
|
||||
# aifs: AIFS (default 2)
|
||||
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
|
||||
# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
|
||||
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191,
|
||||
# 16383, 32767)
|
||||
# cwmax: cwMax (same values as cwMin, cwMax >= cwMin)
|
||||
# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
|
||||
# bursting
|
||||
#
|
||||
@ -337,8 +343,9 @@ ignore_broadcast_ssid=0
|
||||
# note - txop_limit is in units of 32microseconds
|
||||
# note - acm is admission control mandatory flag. 0 = admission control not
|
||||
# required, 1 = mandatory
|
||||
# note - here cwMin and cmMax are in exponent form. the actual cw value used
|
||||
# will be (2^n)-1 where n is the value given here
|
||||
# note - Here cwMin and cmMax are in exponent form. The actual cw value used
|
||||
# will be (2^n)-1 where n is the value given here. The allowed range for these
|
||||
# wmm_ac_??_{cwmin,cwmax} is 0..15 with cwmax >= cwmin.
|
||||
#
|
||||
wmm_enabled=1
|
||||
#
|
||||
@ -575,14 +582,16 @@ wmm_ac_vo_acm=0
|
||||
# 0 = Not supported (default)
|
||||
# 1 = Supported
|
||||
#
|
||||
# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
|
||||
# Compressed Steering Number of Beamformer Antennas Supported:
|
||||
# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4]
|
||||
# Beamformee's capability indicating the maximum number of beamformer
|
||||
# antennas the beamformee can support when sending compressed beamforming
|
||||
# feedback
|
||||
# If SU beamformer capable, set to maximum value minus 1
|
||||
# else reserved (default)
|
||||
#
|
||||
# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
|
||||
# Number of Sounding Dimensions:
|
||||
# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4]
|
||||
# Beamformer's capability indicating the maximum value of the NUM_STS parameter
|
||||
# in the TXVECTOR of a VHT NDP
|
||||
# If SU beamformer capable, set to maximum value minus 1
|
||||
@ -593,11 +602,6 @@ wmm_ac_vo_acm=0
|
||||
# 0 = Not supported or sent by Non-AP STA (default)
|
||||
# 1 = Supported
|
||||
#
|
||||
# MU Beamformee Capable: [MU-BEAMFORMEE]
|
||||
# Indicates support for operation as an MU beamformee
|
||||
# 0 = Not supported or sent by AP (default)
|
||||
# 1 = Supported
|
||||
#
|
||||
# VHT TXOP PS: [VHT-TXOP-PS]
|
||||
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
|
||||
# or whether or not the STA is in VHT TXOP Power Save mode
|
||||
@ -764,6 +768,12 @@ eap_server=0
|
||||
# 2 = check all CRLs in the certificate path
|
||||
#check_crl=1
|
||||
|
||||
# TLS Session Lifetime in seconds
|
||||
# This can be used to allow TLS sessions to be cached and resumed with an
|
||||
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
|
||||
# (default: 0 = session caching and resumption disabled)
|
||||
#tls_session_lifetime=3600
|
||||
|
||||
# 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.
|
||||
@ -787,7 +797,7 @@ eap_server=0
|
||||
# is in DSA parameters format, it will be automatically converted into DH
|
||||
# params. This parameter is required if anonymous EAP-FAST is used.
|
||||
# You can generate DH parameters file with OpenSSL, e.g.,
|
||||
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
|
||||
# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
|
||||
#dh_file=/etc/hostapd.dh.pem
|
||||
|
||||
# OpenSSL cipher string
|
||||
@ -1247,6 +1257,11 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
|
||||
#pmk_r1_push=1
|
||||
|
||||
# Whether to enable FT-over-DS
|
||||
# 0 = FT-over-DS disabled
|
||||
# 1 = FT-over-DS enabled (default)
|
||||
#ft_over_ds=1
|
||||
|
||||
##### Neighbor table ##########################################################
|
||||
# Maximum number of entries kept in AP table (either for neigbor table or for
|
||||
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||
@ -1264,6 +1279,43 @@ own_ip_addr=127.0.0.1
|
||||
# default: 60
|
||||
#ap_table_expiration_time=3600
|
||||
|
||||
# Maximum number of stations to track on the operating channel
|
||||
# This can be used to detect dualband capable stations before they have
|
||||
# associated, e.g., to provide guidance on which colocated BSS to use.
|
||||
# Default: 0 (disabled)
|
||||
#track_sta_max_num=100
|
||||
|
||||
# Maximum age of a station tracking entry in seconds
|
||||
# Default: 180
|
||||
#track_sta_max_age=180
|
||||
|
||||
# Do not reply to group-addressed Probe Request from a station that was seen on
|
||||
# another radio.
|
||||
# Default: Disabled
|
||||
#
|
||||
# This can be used with enabled track_sta_max_num configuration on another
|
||||
# interface controlled by the same hostapd process to restrict Probe Request
|
||||
# frame handling from replying to group-addressed Probe Request frames from a
|
||||
# station that has been detected to be capable of operating on another band,
|
||||
# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when
|
||||
# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
|
||||
#
|
||||
# Note: Enabling this can cause connectivity issues and increase latency for
|
||||
# discovering the AP.
|
||||
#no_probe_resp_if_seen_on=wlan1
|
||||
|
||||
# Reject authentication from a station that was seen on another radio.
|
||||
# Default: Disabled
|
||||
#
|
||||
# This can be used with enabled track_sta_max_num configuration on another
|
||||
# interface controlled by the same hostapd process to reject authentication
|
||||
# attempts from a station that has been detected to be capable of operating on
|
||||
# another band, e.g., to try to reduce likelihood of the station selecting a
|
||||
# 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
|
||||
#
|
||||
# Note: Enabling this can cause connectivity issues and increase latency for
|
||||
# connecting with the AP.
|
||||
#no_auth_if_seen_on=wlan1
|
||||
|
||||
##### Wi-Fi Protected Setup (WPS) #############################################
|
||||
|
||||
@ -1430,7 +1482,7 @@ own_ip_addr=127.0.0.1
|
||||
# 12-digit, all-numeric code that identifies the consumer package.
|
||||
#upc=123456789012
|
||||
|
||||
# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
|
||||
# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band, ad = 60 GHz)
|
||||
# This value should be set according to RF band(s) supported by the AP if
|
||||
# hw_mode is not set. For dual band dual concurrent devices, this needs to be
|
||||
# set to ag to allow both RF bands to be advertized.
|
||||
@ -1490,6 +1542,13 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = enabled
|
||||
#proxy_arp=1
|
||||
|
||||
# IPv6 Neighbor Advertisement multicast-to-unicast conversion
|
||||
# This can be used with Proxy ARP to allow multicast NAs to be forwarded to
|
||||
# associated STAs using link layer unicast delivery.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#na_mcast_to_ucast=0
|
||||
|
||||
##### IEEE 802.11u-2011 #######################################################
|
||||
|
||||
# Enable Interworking service
|
||||
@ -1738,6 +1797,32 @@ own_ip_addr=127.0.0.1
|
||||
#
|
||||
#osu_server_uri=...
|
||||
|
||||
##### Fast Session Transfer (FST) support #####################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
# option CONFIG_FST is set while compiling hostapd. They allow this interface
|
||||
# to be a part of FST setup.
|
||||
#
|
||||
# FST is the transfer of a session from a channel to another channel, in the
|
||||
# same or different frequency bands.
|
||||
#
|
||||
# For detals, see IEEE Std 802.11ad-2012.
|
||||
|
||||
# Identifier of an FST Group the interface belongs to.
|
||||
#fst_group_id=bond0
|
||||
|
||||
# Interface priority within the FST Group.
|
||||
# Announcing a higher priority for an interface means declaring it more
|
||||
# preferable for FST switch.
|
||||
# fst_priority is in 1..255 range with 1 being the lowest priority.
|
||||
#fst_priority=100
|
||||
|
||||
# Default LLT value for this interface in milliseconds. The value used in case
|
||||
# no value provided during session setup. Default is 50 ms.
|
||||
# fst_llt is in 1..4294967 range (due to spec limitation, see 10.32.2.2
|
||||
# Transitioning between states).
|
||||
#fst_llt=100
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
|
@ -10,22 +10,23 @@
|
||||
#include <dirent.h>
|
||||
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/edit.h"
|
||||
#include "common/version.h"
|
||||
|
||||
|
||||
static const char *hostapd_cli_version =
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
|
||||
static const char *hostapd_cli_license =
|
||||
static const char *const hostapd_cli_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"See README for more details.\n";
|
||||
|
||||
static const char *hostapd_cli_full_license =
|
||||
static const char *const hostapd_cli_full_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
@ -56,7 +57,7 @@ static const char *hostapd_cli_full_license =
|
||||
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n";
|
||||
|
||||
static const char *commands_help =
|
||||
static const char *const commands_help =
|
||||
"Commands:\n"
|
||||
" mib get MIB variables (dot1x, dot11, radius)\n"
|
||||
" sta <addr> get MIB variables for one station\n"
|
||||
@ -96,6 +97,7 @@ static int hostapd_cli_attached = 0;
|
||||
#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
|
||||
#endif /* CONFIG_CTRL_IFACE_DIR */
|
||||
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
|
||||
static const char *client_socket_dir = NULL;
|
||||
|
||||
static char *ctrl_ifname = NULL;
|
||||
static const char *pid_file = NULL;
|
||||
@ -111,13 +113,15 @@ static void usage(void)
|
||||
"\n"
|
||||
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
|
||||
"[-a<path>] \\\n"
|
||||
" [-G<ping interval>] [command..]\n"
|
||||
" [-P<pid file>] [-G<ping interval>] [command..]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h help (show this usage text)\n"
|
||||
" -v shown version information\n"
|
||||
" -p<path> path to find control sockets (default: "
|
||||
"/var/run/hostapd)\n"
|
||||
" -s<dir_path> dir path to open client sockets (default: "
|
||||
CONFIG_CTRL_IFACE_DIR ")\n"
|
||||
" -a<file> run in daemon mode executing the action file "
|
||||
"based on events\n"
|
||||
" from hostapd\n"
|
||||
@ -144,7 +148,14 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
return NULL;
|
||||
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
|
||||
|
||||
ctrl_conn = wpa_ctrl_open(cfile);
|
||||
if (client_socket_dir && client_socket_dir[0] &&
|
||||
access(client_socket_dir, F_OK) < 0) {
|
||||
perror(client_socket_dir);
|
||||
free(cfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
|
||||
free(cfile);
|
||||
return ctrl_conn;
|
||||
}
|
||||
@ -541,7 +552,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char buf[256];
|
||||
char ssid_hex[2 * 32 + 1];
|
||||
char ssid_hex[2 * SSID_MAX_LEN + 1];
|
||||
char key_hex[2 * 64 + 1];
|
||||
int i;
|
||||
|
||||
@ -552,7 +563,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
ssid_hex[0] = '\0';
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (i = 0; i < SSID_MAX_LEN; i++) {
|
||||
if (argv[0][i] == '\0')
|
||||
break;
|
||||
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
|
||||
@ -921,6 +932,35 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
int res;
|
||||
int i;
|
||||
int total;
|
||||
|
||||
if (argc <= 0) {
|
||||
printf("FST command: parameters are required.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
|
||||
argv[i]);
|
||||
if (os_snprintf_error(sizeof(cmd) - total, res)) {
|
||||
printf("Too long fst command.\n");
|
||||
return -1;
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
@ -1009,12 +1049,31 @@ static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
int res;
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
|
||||
argc >= 1 ? " " : "",
|
||||
argc >= 1 ? argv[0] : "",
|
||||
argc == 2 ? " " : "",
|
||||
argc == 2 ? argv[1] : "");
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long option\n");
|
||||
return -1;
|
||||
}
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
};
|
||||
|
||||
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "ping", hostapd_cli_cmd_ping },
|
||||
{ "mib", hostapd_cli_cmd_mib },
|
||||
{ "relog", hostapd_cli_cmd_relog },
|
||||
@ -1048,6 +1107,9 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "get_config", hostapd_cli_cmd_get_config },
|
||||
{ "help", hostapd_cli_cmd_help },
|
||||
{ "interface", hostapd_cli_cmd_interface },
|
||||
#ifdef CONFIG_FST
|
||||
{ "fst", hostapd_cli_cmd_fst },
|
||||
#endif /* CONFIG_FST */
|
||||
{ "level", hostapd_cli_cmd_level },
|
||||
{ "license", hostapd_cli_cmd_license },
|
||||
{ "quit", hostapd_cli_cmd_quit },
|
||||
@ -1063,13 +1125,14 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "reload", hostapd_cli_cmd_reload },
|
||||
{ "disable", hostapd_cli_cmd_disable },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush },
|
||||
{ "log_level", hostapd_cli_cmd_log_level },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||
const struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
@ -1284,7 +1347,7 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "a:BhG:i:p:v");
|
||||
c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -1310,6 +1373,12 @@ int main(int argc, char *argv[])
|
||||
case 'p':
|
||||
ctrl_iface_dir = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pid_file = optarg;
|
||||
break;
|
||||
case 's':
|
||||
client_socket_dir = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/ap_drv_ops.h"
|
||||
#include "fst/fst.h"
|
||||
#include "config_file.h"
|
||||
#include "eap_register.h"
|
||||
#include "ctrl_iface.h"
|
||||
@ -533,6 +534,28 @@ static int gen_uuid(const char *txt_addr)
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
||||
#ifndef HOSTAPD_CLEANUP_INTERVAL
|
||||
#define HOSTAPD_CLEANUP_INTERVAL 10
|
||||
#endif /* HOSTAPD_CLEANUP_INTERVAL */
|
||||
|
||||
static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
hostapd_periodic_iface(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Periodic cleanup tasks */
|
||||
static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = eloop_ctx;
|
||||
|
||||
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
|
||||
hostapd_periodic, interfaces, NULL);
|
||||
hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct hapd_interfaces interfaces;
|
||||
@ -561,6 +584,7 @@ int main(int argc, char *argv[])
|
||||
interfaces.global_iface_path = NULL;
|
||||
interfaces.global_iface_name = NULL;
|
||||
interfaces.global_ctrl_sock = -1;
|
||||
interfaces.global_ctrl_dst = NULL;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
|
||||
@ -661,10 +685,24 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (hostapd_global_init(&interfaces, entropy_file)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initilize global context");
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize global context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
|
||||
hostapd_periodic, &interfaces, NULL);
|
||||
|
||||
if (fst_global_init()) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to initialize global FST context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
|
||||
if (!fst_global_add_ctrl(fst_ctrl_cli))
|
||||
wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
|
||||
#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
|
||||
|
||||
/* Allocate and parse configuration for full interface files */
|
||||
for (i = 0; i < interfaces.count; i++) {
|
||||
interfaces.iface[i] = hostapd_interface_init(&interfaces,
|
||||
@ -749,6 +787,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
|
||||
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
|
||||
hostapd_global_deinit(pid_file);
|
||||
os_free(pid_file);
|
||||
|
||||
@ -758,6 +797,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
os_free(bss_config);
|
||||
|
||||
fst_global_deinit();
|
||||
|
||||
os_program_deinit();
|
||||
|
||||
return ret;
|
||||
|
@ -67,7 +67,13 @@ OBJS += ../../src/crypto/sha256-internal.o
|
||||
|
||||
CFLAGS += $(shell xml2-config --cflags)
|
||||
LIBS += $(shell xml2-config --libs)
|
||||
|
||||
# Allow static/custom linking of libcurl.
|
||||
ifdef CUST_CURL_LINKAGE
|
||||
LIBS += ${CUST_CURL_LINKAGE}
|
||||
else
|
||||
LIBS += -lcurl
|
||||
endif
|
||||
|
||||
CFLAGS += -DEAP_TLS_OPENSSL
|
||||
LIBS += -lssl -lcrypto
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "crypto/sha256.h"
|
||||
#include "osu_client.h"
|
||||
|
||||
const char *spp_xsd_fname = "spp.xsd";
|
||||
|
||||
|
||||
void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
|
||||
{
|
||||
@ -540,6 +542,7 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
|
||||
uri);
|
||||
write_result(ctx, "Unsupported location for addMO to "
|
||||
"add PPS MO (extra directory): '%s'", uri);
|
||||
free(fqdn);
|
||||
return -1;
|
||||
}
|
||||
*pos = '\0'; /* remove trailing slash and PPS node name */
|
||||
@ -547,8 +550,9 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
|
||||
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);
|
||||
wpa_printf(MSG_INFO,
|
||||
"FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
|
||||
fqdn, (int) ctx->server_dnsname_count);
|
||||
write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
|
||||
fqdn);
|
||||
free(fqdn);
|
||||
@ -2094,10 +2098,14 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
}
|
||||
|
||||
ctx->no_reconnect = 1;
|
||||
if (methods & 0x02)
|
||||
if (methods & 0x02) {
|
||||
wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
|
||||
res = cmd_prov(ctx, url);
|
||||
else if (methods & 0x01)
|
||||
} else if (methods & 0x01) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Calling cmd_oma_dm_prov from osu_connect");
|
||||
res = cmd_oma_dm_prov(ctx, url);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "Remove OSU network connection");
|
||||
write_summary(ctx, "Remove OSU network connection");
|
||||
@ -2139,7 +2147,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
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",
|
||||
wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
|
||||
fname);
|
||||
write_result(ctx, "No OSU providers available");
|
||||
return -1;
|
||||
@ -2290,12 +2298,19 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
}
|
||||
|
||||
if (connect == 2) {
|
||||
if (last->methods & 0x02)
|
||||
if (last->methods & 0x02) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Calling cmd_prov from cmd_osu_select");
|
||||
ret = cmd_prov(ctx, last->url);
|
||||
else if (last->methods & 0x01)
|
||||
} else if (last->methods & 0x01) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Calling cmd_oma_dm_prov from cmd_osu_select");
|
||||
ret = cmd_oma_dm_prov(ctx, last->url);
|
||||
else
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"No supported OSU provisioning method");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (connect)
|
||||
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
|
||||
last->url, last->methods,
|
||||
@ -2690,7 +2705,7 @@ static char * get_hostname(const char *url)
|
||||
|
||||
end = os_strchr(pos, '/');
|
||||
end2 = os_strchr(pos, ':');
|
||||
if (end && end2 && end2 < end)
|
||||
if ((end && end2 && end2 < end) || (!end && end2))
|
||||
end = end2;
|
||||
if (end)
|
||||
end--;
|
||||
@ -2720,8 +2735,8 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
int found;
|
||||
char *host = NULL;
|
||||
|
||||
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d)",
|
||||
!ctx->no_osu_cert_validation);
|
||||
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
|
||||
!ctx->no_osu_cert_validation, ctx->server_url);
|
||||
|
||||
host = get_hostname(ctx->server_url);
|
||||
|
||||
@ -2810,17 +2825,21 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
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);
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i] Looking for icon file name '%s' match",
|
||||
j, 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)
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i] Comparing to '%s' uri_len=%d name_len=%d",
|
||||
i, logo->uri, (int) uri_len, (int) name_len);
|
||||
if (uri_len < 1 + name_len) {
|
||||
wpa_printf(MSG_INFO, "URI Length is too short");
|
||||
continue;
|
||||
}
|
||||
pos = &logo->uri[uri_len - name_len - 1];
|
||||
if (*pos != '/')
|
||||
continue;
|
||||
@ -2847,17 +2866,30 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
for (i = 0; i < cert->num_logo; i++) {
|
||||
struct http_logo *logo = &cert->logo[i];
|
||||
|
||||
if (logo->hash_len != 32)
|
||||
if (logo->hash_len != 32) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i][%i] Icon hash length invalid (should be 32): %d",
|
||||
j, i, (int) logo->hash_len);
|
||||
continue;
|
||||
}
|
||||
if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"[%u][%u] Icon hash did not match", j, i);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
|
||||
logo->hash, 32);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
|
||||
ctx->icon_hash[j], 32);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
wpa_printf(MSG_INFO, "No icon hash match found");
|
||||
write_result(ctx, "No icon hash match found");
|
||||
wpa_printf(MSG_INFO,
|
||||
"No icon hash match (by hash) found");
|
||||
write_result(ctx,
|
||||
"No icon hash match (by hash) found");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -2955,6 +2987,7 @@ static void usage(void)
|
||||
" [-w<wpa_supplicant ctrl_iface dir>] "
|
||||
"[-r<result file>] [-f<debug file>] \\\n"
|
||||
" [-s<summary file>] \\\n"
|
||||
" [-x<spp.xsd file name>] \\\n"
|
||||
" <command> [arguments..]\n"
|
||||
"commands:\n"
|
||||
"- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
|
||||
@ -2996,7 +3029,7 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
|
||||
c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -3034,6 +3067,9 @@ int main(int argc, char *argv[])
|
||||
case 'w':
|
||||
wpas_ctrl_path = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
spp_xsd_fname = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
@ -3108,6 +3144,7 @@ int main(int argc, char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
ctx.ca_fname = argv[optind + 2];
|
||||
wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
|
||||
cmd_prov(&ctx, argv[optind + 1]);
|
||||
} else if (strcmp(argv[optind], "sim_prov") == 0) {
|
||||
if (argc - optind < 2) {
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "osu_client.h"
|
||||
|
||||
|
||||
extern const char *spp_xsd_fname;
|
||||
|
||||
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
|
||||
const char *session_id,
|
||||
const char *spp_status,
|
||||
@ -59,7 +61,7 @@ static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = xml_validate(xctx, node, "spp.xsd", &err);
|
||||
ret = xml_validate(xctx, node, spp_xsd_fname, &err);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
|
||||
write_summary(ctx, "SPP XML schema validation failed");
|
||||
@ -77,9 +79,14 @@ static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
|
||||
xml_node_t *fnode, *tnds;
|
||||
char *str;
|
||||
|
||||
errno = 0;
|
||||
fnode = node_from_file(ctx, fname);
|
||||
if (!fnode)
|
||||
if (!fnode) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to create XML node from file: %s, possible error: %s",
|
||||
fname, strerror(errno));
|
||||
return;
|
||||
}
|
||||
tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
|
||||
xml_node_free(ctx, fnode);
|
||||
if (!tnds)
|
||||
@ -952,7 +959,9 @@ int cmd_prov(struct hs20_osu_client *ctx, const char *url)
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "Credential provisioning requested");
|
||||
wpa_printf(MSG_INFO,
|
||||
"Credential provisioning requested - URL: %s ca_fname: %s",
|
||||
url, ctx->ca_fname ? ctx->ca_fname : "N/A");
|
||||
|
||||
os_free(ctx->server_url);
|
||||
ctx->server_url = os_strdup(url);
|
||||
|
398
contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
Normal file
398
contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
Normal file
@ -0,0 +1,398 @@
|
||||
This patch adds support for TLS SessionTicket extension (RFC 5077) for
|
||||
the parts used by EAP-FAST (RFC 4851).
|
||||
|
||||
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
|
||||
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
|
||||
|
||||
OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
|
||||
will need to be enabled by adding enable-tlsext to config script
|
||||
command line.
|
||||
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
|
||||
--- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
|
||||
@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
|
||||
goto f_err;
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ /* check if we want to resume the session based on external pre-shared secret */
|
||||
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
|
||||
+ SSL_CIPHER *pref_cipher = NULL;
|
||||
+
|
||||
+ s->session->master_key_length = sizeof(s->session->master_key);
|
||||
+ if (s->tls_session_secret_cb(s, s->session->master_key,
|
||||
+ &s->session->master_key_length,
|
||||
+ NULL, &pref_cipher,
|
||||
+ s->tls_session_secret_cb_arg)) {
|
||||
+ s->session->cipher = pref_cipher ?
|
||||
+ pref_cipher : ssl_get_cipher_by_char(s, p + j);
|
||||
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
|
||||
+ }
|
||||
+ }
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
if (j != 0 && j == s->session->session_id_length
|
||||
&& memcmp(p, s->session->session_id, j) == 0) {
|
||||
if (s->sid_ctx_length != s->session->sid_ctx_length
|
||||
@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
|
||||
{
|
||||
int ok;
|
||||
long n;
|
||||
- /*
|
||||
- * If we have no ticket or session ID is non-zero length (a match of a
|
||||
- * non-zero session length would never reach here) it cannot be a resumed
|
||||
- * session.
|
||||
- */
|
||||
- if (!s->session->tlsext_tick || s->session->session_id_length)
|
||||
+ /* If we have no ticket it cannot be a resumed session. */
|
||||
+ if (!s->session->tlsext_tick)
|
||||
return 1;
|
||||
/*
|
||||
* this function is called when we really expect a Certificate message,
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
|
||||
--- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
|
||||
@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
|
||||
goto err;
|
||||
}
|
||||
+
|
||||
+ /* Check if we want to use external pre-shared secret for this
|
||||
+ * handshake for not reused session only. We need to generate
|
||||
+ * server_random before calling tls_session_secret_cb in order to allow
|
||||
+ * SessionTicket processing to use it in key derivation. */
|
||||
+ {
|
||||
+ unsigned long Time;
|
||||
+ unsigned char *pos;
|
||||
+ Time = (unsigned long)time(NULL); /* Time */
|
||||
+ pos = s->s3->server_random;
|
||||
+ l2n(Time, pos);
|
||||
+ if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
|
||||
+ al = SSL_AD_INTERNAL_ERROR;
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
|
||||
+ SSL_CIPHER *pref_cipher = NULL;
|
||||
+
|
||||
+ s->session->master_key_length = sizeof(s->session->master_key);
|
||||
+ if (s->tls_session_secret_cb(s, s->session->master_key,
|
||||
+ &s->session->master_key_length,
|
||||
+ ciphers, &pref_cipher,
|
||||
+ s->tls_session_secret_cb_arg)) {
|
||||
+ s->hit = 1;
|
||||
+ s->session->ciphers = ciphers;
|
||||
+ s->session->verify_result = X509_V_OK;
|
||||
+
|
||||
+ ciphers = NULL;
|
||||
+
|
||||
+ /* check if some cipher was preferred by call back */
|
||||
+ pref_cipher = pref_cipher ? pref_cipher :
|
||||
+ ssl3_choose_cipher(s, s->session->ciphers,
|
||||
+ SSL_get_ciphers(s));
|
||||
+ if (pref_cipher == NULL) {
|
||||
+ al = SSL_AD_HANDSHAKE_FAILURE;
|
||||
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+
|
||||
+ s->session->cipher = pref_cipher;
|
||||
+
|
||||
+ if (s->cipher_list)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list);
|
||||
+
|
||||
+ if (s->cipher_list_by_id)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
||||
+
|
||||
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ }
|
||||
+ }
|
||||
#endif
|
||||
/*
|
||||
* Worst case, we will use the NULL compression, but if we have other
|
||||
@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
|
||||
unsigned char *buf;
|
||||
unsigned char *p, *d;
|
||||
int i, sl;
|
||||
- unsigned long l, Time;
|
||||
+ unsigned long l;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
+ unsigned long Time;
|
||||
+#endif
|
||||
|
||||
if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
|
||||
buf = (unsigned char *)s->init_buf->data;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
p = s->s3->server_random;
|
||||
+ /* Generate server_random if it was not needed previously */
|
||||
Time = (unsigned long)time(NULL); /* Time */
|
||||
l2n(Time, p);
|
||||
if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
|
||||
return -1;
|
||||
+#endif
|
||||
/* Do the message type and length last */
|
||||
d = p = &(buf[4]);
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
|
||||
@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
|
||||
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
|
||||
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
|
||||
+ {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
|
||||
@@ -349,6 +349,7 @@ extern "C" {
|
||||
* function parameters used to prototype callbacks in SSL_CTX.
|
||||
*/
|
||||
typedef struct ssl_st *ssl_crock_st;
|
||||
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
|
||||
|
||||
/* used to hold info on the particular ciphers used */
|
||||
typedef struct ssl_cipher_st {
|
||||
@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
|
||||
|
||||
DECLARE_STACK_OF(SSL_CIPHER)
|
||||
|
||||
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
|
||||
+ int len, void *arg);
|
||||
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
|
||||
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
|
||||
+ SSL_CIPHER **cipher, void *arg);
|
||||
+
|
||||
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
|
||||
typedef struct ssl_method_st {
|
||||
int version;
|
||||
@@ -1116,6 +1123,18 @@ struct ssl_st {
|
||||
int tlsext_ocsp_resplen;
|
||||
/* RFC4507 session ticket expected to be received or sent */
|
||||
int tlsext_ticket_expected;
|
||||
+
|
||||
+ /* TLS Session Ticket extension override */
|
||||
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
|
||||
+
|
||||
+ /* TLS Session Ticket extension callback */
|
||||
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
|
||||
+ void *tls_session_ticket_ext_cb_arg;
|
||||
+
|
||||
+ /* TLS pre-shared secret session resumption */
|
||||
+ tls_session_secret_cb_fn tls_session_secret_cb;
|
||||
+ void *tls_session_secret_cb_arg;
|
||||
+
|
||||
SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */
|
||||
# define session_ctx initial_ctx
|
||||
# else
|
||||
@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
|
||||
int SSL_COMP_add_compression_method(int id, void *cm);
|
||||
# endif
|
||||
|
||||
+/* TLS extensions functions */
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg);
|
||||
+
|
||||
+/* Pre-shared secret session resumption functions */
|
||||
+int SSL_set_session_secret_cb(SSL *s,
|
||||
+ tls_session_secret_cb_fn tls_session_secret_cb,
|
||||
+ void *arg);
|
||||
+
|
||||
/* BEGIN ERROR CODES */
|
||||
/*
|
||||
* The following lines are auto generated by the script mkerr.pl. Any changes
|
||||
@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
|
||||
# define SSL_F_TLS1_ENC 210
|
||||
# define SSL_F_TLS1_SETUP_KEY_BLOCK 211
|
||||
# define SSL_F_WRITE_PENDING 212
|
||||
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
|
||||
|
||||
/* Reason codes. */
|
||||
# define SSL_R_APP_DATA_IN_HANDSHAKE 100
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
|
||||
@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
|
||||
return (s->session_timeout);
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+int SSL_set_session_secret_cb(
|
||||
+ SSL *s,
|
||||
+ int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
|
||||
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
|
||||
+ SSL_CIPHER **cipher, void *arg), void *arg)
|
||||
+{
|
||||
+ if (s == NULL)
|
||||
+ return 0;
|
||||
+ s->tls_session_secret_cb = tls_session_secret_cb;
|
||||
+ s->tls_session_secret_cb_arg = arg;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg)
|
||||
+{
|
||||
+ if (s == NULL)
|
||||
+ return 0;
|
||||
+ s->tls_session_ticket_ext_cb = cb;
|
||||
+ s->tls_session_ticket_ext_cb_arg = arg;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
|
||||
+{
|
||||
+ if (s->version >= TLS1_VERSION) {
|
||||
+ if (s->tlsext_session_ticket) {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ s->tlsext_session_ticket = NULL;
|
||||
+ }
|
||||
+
|
||||
+ s->tlsext_session_ticket = OPENSSL_malloc(
|
||||
+ sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
|
||||
+ if (!s->tlsext_session_ticket) {
|
||||
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (ext_data) {
|
||||
+ s->tlsext_session_ticket->length = ext_len;
|
||||
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
|
||||
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
|
||||
+ } else {
|
||||
+ s->tlsext_session_ticket->length = 0;
|
||||
+ s->tlsext_session_ticket->data = NULL;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
typedef struct timeout_param_st {
|
||||
SSL_CTX *ctx;
|
||||
long time;
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
|
||||
--- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
|
||||
@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
|
||||
|
||||
void tls1_free(SSL *s)
|
||||
{
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ if (s->tlsext_session_ticket) {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ }
|
||||
+#endif
|
||||
ssl3_free(s);
|
||||
}
|
||||
|
||||
@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
int ticklen;
|
||||
if (!s->new_session && s->session && s->session->tlsext_tick)
|
||||
ticklen = s->session->tlsext_ticklen;
|
||||
- else
|
||||
+ else if (s->session && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data) {
|
||||
+ ticklen = s->tlsext_session_ticket->length;
|
||||
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||
+ if (!s->session->tlsext_tick)
|
||||
+ return NULL;
|
||||
+ memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
|
||||
+ ticklen);
|
||||
+ s->session->tlsext_ticklen = ticklen;
|
||||
+ } else
|
||||
ticklen = 0;
|
||||
+ if (ticklen == 0 && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data == NULL)
|
||||
+ goto skip_ext;
|
||||
/*
|
||||
* Check for enough room 2 for extension type, 2 for len rest for
|
||||
* ticket
|
||||
@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
ret += ticklen;
|
||||
}
|
||||
}
|
||||
+skip_ext:
|
||||
|
||||
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
|
||||
s->version != DTLS1_VERSION) {
|
||||
@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
|
||||
if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
|
||||
return 0;
|
||||
renegotiate_seen = 1;
|
||||
+ } else if (type == TLSEXT_TYPE_session_ticket) {
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(s, data, size,
|
||||
+ s->tls_session_ticket_ext_cb_arg))
|
||||
+ {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
} else if (type == TLSEXT_TYPE_status_request &&
|
||||
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
|
||||
|
||||
@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
|
||||
}
|
||||
tlsext_servername = 1;
|
||||
} else if (type == TLSEXT_TYPE_session_ticket) {
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(
|
||||
+ s, data, size,
|
||||
+ s->tls_session_ticket_ext_cb_arg)) {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|
||||
|| (size > 0)) {
|
||||
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
|
||||
@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
|
||||
s->tlsext_ticket_expected = 1;
|
||||
return 0; /* Cache miss */
|
||||
}
|
||||
+ if (s->tls_session_secret_cb) {
|
||||
+ /* Indicate cache miss here and instead of
|
||||
+ * generating the session from ticket now,
|
||||
+ * trigger abbreviated handshake based on
|
||||
+ * external mechanism to calculate the master
|
||||
+ * secret later. */
|
||||
+ return 0;
|
||||
+ }
|
||||
return tls_decrypt_ticket(s, p, size, session_id, len, ret);
|
||||
}
|
||||
p += size;
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
|
||||
--- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
|
||||
@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
|
||||
# define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
|
||||
# endif
|
||||
|
||||
+/* TLS extension struct */
|
||||
+struct tls_session_ticket_ext_st {
|
||||
+ unsigned short length;
|
||||
+ void *data;
|
||||
+};
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
|
||||
--- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
|
||||
+++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
|
||||
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
|
||||
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
|
||||
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
|
||||
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
|
||||
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
|
||||
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
|
@ -459,10 +459,14 @@ int accounting_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct os_time now;
|
||||
|
||||
/* Acct-Session-Id should be unique over reboots. If reliable clock is
|
||||
* not available, this could be replaced with reboot counter, etc. */
|
||||
/* Acct-Session-Id should be unique over reboots. Using a random number
|
||||
* is preferred. If that is not available, take the current time. Mix
|
||||
* in microseconds to make this more likely to be unique. */
|
||||
os_get_time(&now);
|
||||
hapd->acct_session_id_hi = now.sec;
|
||||
if (os_get_random((u8 *) &hapd->acct_session_id_hi,
|
||||
sizeof(hapd->acct_session_id_hi)) < 0)
|
||||
hapd->acct_session_id_hi = now.sec;
|
||||
hapd->acct_session_id_hi ^= now.usec;
|
||||
|
||||
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
||||
accounting_receive, hapd))
|
||||
@ -475,7 +479,7 @@ int accounting_init(struct hostapd_data *hapd)
|
||||
|
||||
|
||||
/**
|
||||
* accounting_deinit: Deinitilize accounting
|
||||
* accounting_deinit: Deinitialize accounting
|
||||
* @hapd: hostapd BSS data
|
||||
*/
|
||||
void accounting_deinit(struct hostapd_data *hapd)
|
||||
|
@ -479,16 +479,10 @@ static int acs_usable_chan(struct hostapd_channel_data *chan)
|
||||
static int is_in_chanlist(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan)
|
||||
{
|
||||
int *entry;
|
||||
|
||||
if (!iface->conf->chanlist)
|
||||
if (!iface->conf->acs_ch_list.num)
|
||||
return 1;
|
||||
|
||||
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
|
||||
if (*entry == chan->chan)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
|
||||
}
|
||||
|
||||
|
||||
@ -900,6 +894,9 @@ static int acs_request_scan(struct hostapd_iface *iface)
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
*freq++ = chan->freq;
|
||||
}
|
||||
*freq = 0;
|
||||
|
@ -172,6 +172,7 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
|
||||
conf->ap_table_max_size = 255;
|
||||
conf->ap_table_expiration_time = 60;
|
||||
conf->track_sta_max_age = 180;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
conf->ignore_probe_probability = 0.0;
|
||||
@ -181,6 +182,8 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->corrupt_gtk_rekey_mic_probability = 0.0;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
conf->acs = 0;
|
||||
conf->acs_ch_list.num = 0;
|
||||
#ifdef CONFIG_ACS
|
||||
conf->acs_num_scans = 5;
|
||||
#endif /* CONFIG_ACS */
|
||||
@ -559,6 +562,13 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
os_free(conf->server_id);
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpabuf_free(conf->own_ie_override);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_free(conf->no_probe_resp_if_seen_on);
|
||||
os_free(conf->no_auth_if_seen_on);
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
|
||||
@ -579,7 +589,7 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||
os_free(conf->bss);
|
||||
os_free(conf->supported_rates);
|
||||
os_free(conf->basic_rates);
|
||||
os_free(conf->chanlist);
|
||||
os_free(conf->acs_ch_list.range);
|
||||
os_free(conf->driver_params);
|
||||
#ifdef CONFIG_ACS
|
||||
os_free(conf->acs_chan_bias);
|
||||
@ -817,9 +827,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
|
||||
if (full_config && bss->wps_state && bss->wpa &&
|
||||
(!(bss->wpa & 2) ||
|
||||
!(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
|
||||
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
|
||||
"WPA2/CCMP forced WPS to be disabled");
|
||||
"WPA2/CCMP/GCMP forced WPS to be disabled");
|
||||
bss->wps_state = 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
@ -841,6 +851,29 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_check_cw(struct hostapd_config *conf, int queue)
|
||||
{
|
||||
int tx_cwmin = conf->tx_queue[queue].cwmin;
|
||||
int tx_cwmax = conf->tx_queue[queue].cwmax;
|
||||
int ac_cwmin = conf->wmm_ac_params[queue].cwmin;
|
||||
int ac_cwmax = conf->wmm_ac_params[queue].cwmax;
|
||||
|
||||
if (tx_cwmin > tx_cwmax) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid TX queue cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
|
||||
tx_cwmin, tx_cwmax);
|
||||
return -1;
|
||||
}
|
||||
if (ac_cwmin > ac_cwmax) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid WMM AC cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
|
||||
ac_cwmin, ac_cwmax);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
{
|
||||
size_t i;
|
||||
@ -870,6 +903,11 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
if (hostapd_config_check_cw(conf, i))
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++) {
|
||||
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
|
||||
return -1;
|
||||
@ -937,10 +975,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
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)
|
||||
if (full_config) {
|
||||
bss->wpa_group = WPA_CIPHER_NONE;
|
||||
bss->wpa_pairwise = WPA_CIPHER_NONE;
|
||||
bss->rsn_pairwise = WPA_CIPHER_NONE;
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / Configuration definitions and helpers 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.
|
||||
@ -12,8 +12,10 @@
|
||||
#include "common/defs.h"
|
||||
#include "ip_addr.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst.h"
|
||||
|
||||
/**
|
||||
* mesh_conf - local MBSS state and settings
|
||||
@ -31,8 +33,8 @@ struct mesh_conf {
|
||||
u8 mesh_sp_id;
|
||||
/* Authentication Protocol Identifier */
|
||||
u8 mesh_auth_id;
|
||||
u8 *ies;
|
||||
int ie_len;
|
||||
u8 *rsn_ie;
|
||||
int rsn_ie_len;
|
||||
#define MESH_CONF_SEC_NONE BIT(0)
|
||||
#define MESH_CONF_SEC_AUTH BIT(1)
|
||||
#define MESH_CONF_SEC_AMPE BIT(2)
|
||||
@ -57,8 +59,6 @@ struct hostapd_radius_servers;
|
||||
struct ft_remote_r0kh;
|
||||
struct ft_remote_r1kh;
|
||||
|
||||
#define HOSTAPD_MAX_SSID_LEN 32
|
||||
|
||||
#define NUM_WEP_KEYS 4
|
||||
struct hostapd_wep_keys {
|
||||
u8 idx;
|
||||
@ -78,7 +78,7 @@ typedef enum hostap_security_policy {
|
||||
} secpolicy;
|
||||
|
||||
struct hostapd_ssid {
|
||||
u8 ssid[HOSTAPD_MAX_SSID_LEN];
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
unsigned int ssid_set:1;
|
||||
unsigned int utf8_ssid:1;
|
||||
@ -114,12 +114,10 @@ struct hostapd_vlan {
|
||||
struct hostapd_vlan *next;
|
||||
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int configured;
|
||||
int dynamic_vlan;
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
|
||||
#define DVLAN_CLEAN_BR 0x1
|
||||
#define DVLAN_CLEAN_VLAN 0x2
|
||||
#define DVLAN_CLEAN_VLAN_PORT 0x4
|
||||
#define DVLAN_CLEAN_WLAN_PORT 0x8
|
||||
int clean;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
@ -332,6 +330,7 @@ struct hostapd_bss_config {
|
||||
char *private_key;
|
||||
char *private_key_passwd;
|
||||
int check_crl;
|
||||
unsigned int tls_session_lifetime;
|
||||
char *ocsp_stapling_response;
|
||||
char *dh_file;
|
||||
char *openssl_ciphers;
|
||||
@ -490,6 +489,7 @@ struct hostapd_bss_config {
|
||||
|
||||
int osen;
|
||||
int proxy_arp;
|
||||
int na_mcast_to_ucast;
|
||||
#ifdef CONFIG_HS20
|
||||
int hs20;
|
||||
int disable_dgaf;
|
||||
@ -510,7 +510,7 @@ struct hostapd_bss_config {
|
||||
char file[256];
|
||||
} *hs20_icons;
|
||||
size_t hs20_icons_count;
|
||||
u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
|
||||
u8 osu_ssid[SSID_MAX_LEN];
|
||||
size_t osu_ssid_len;
|
||||
struct hs20_osu_provider {
|
||||
unsigned int friendly_name_count;
|
||||
@ -545,6 +545,7 @@ struct hostapd_bss_config {
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
u8 bss_load_test[5];
|
||||
u8 bss_load_test_set;
|
||||
struct wpabuf *own_ie_override;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define MESH_ENABLED BIT(0)
|
||||
@ -553,6 +554,9 @@ struct hostapd_bss_config {
|
||||
int radio_measurements;
|
||||
|
||||
int vendor_vht;
|
||||
|
||||
char *no_probe_resp_if_seen_on;
|
||||
char *no_auth_if_seen_on;
|
||||
};
|
||||
|
||||
|
||||
@ -568,7 +572,8 @@ struct hostapd_config {
|
||||
int fragm_threshold;
|
||||
u8 send_probe_response;
|
||||
u8 channel;
|
||||
int *chanlist;
|
||||
u8 acs;
|
||||
struct wpa_freq_range_list acs_ch_list;
|
||||
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||
enum {
|
||||
LONG_PREAMBLE = 0,
|
||||
@ -584,6 +589,9 @@ struct hostapd_config {
|
||||
int ap_table_max_size;
|
||||
int ap_table_expiration_time;
|
||||
|
||||
unsigned int track_sta_max_num;
|
||||
unsigned int track_sta_max_age;
|
||||
|
||||
char country[3]; /* first two octets: country code as described in
|
||||
* ISO/IEC 3166-1. Third octet:
|
||||
* ' ' (ascii 32): all environments
|
||||
@ -620,6 +628,7 @@ struct hostapd_config {
|
||||
u16 ht_capab;
|
||||
int ieee80211n;
|
||||
int secondary_channel;
|
||||
int no_pri_sec_switch;
|
||||
int require_ht;
|
||||
int obss_interval;
|
||||
u32 vht_capab;
|
||||
@ -629,6 +638,10 @@ struct hostapd_config {
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
struct fst_iface_cfg fst_cfg;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
u8 p2p_go_ctwindow;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
@ -81,6 +81,22 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
wpabuf_put_data(proberesp, buf, pos - buf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
size_t add = wpabuf_len(hapd->iface->fst_ies);
|
||||
|
||||
if (wpabuf_resize(&beacon, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(beacon, hapd->iface->fst_ies);
|
||||
if (wpabuf_resize(&proberesp, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
|
||||
if (wpabuf_resize(&assocresp, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
if (hapd->wps_beacon_ie) {
|
||||
if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
|
||||
0)
|
||||
@ -217,6 +233,15 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
|
||||
return 0;
|
||||
|
||||
return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpabuf *beacon, *proberesp, *assocresp;
|
||||
@ -281,8 +306,14 @@ 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 |
|
||||
hapd->conf->rsn_pairwise;
|
||||
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
|
||||
(WPA_PROTO_WPA | WPA_PROTO_RSN))
|
||||
params.wpa_pairwise = hapd->conf->wpa_pairwise |
|
||||
hapd->conf->rsn_pairwise;
|
||||
else if (hapd->conf->wpa & WPA_PROTO_RSN)
|
||||
params.wpa_pairwise = hapd->conf->rsn_pairwise;
|
||||
else if (hapd->conf->wpa & WPA_PROTO_WPA)
|
||||
params.wpa_pairwise = hapd->conf->wpa_pairwise;
|
||||
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
|
||||
params.rsn_preauth = hapd->conf->rsn_preauth;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
@ -618,7 +649,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -712,16 +743,100 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int acs_ch_list_all,
|
||||
int **freq_list)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[i];
|
||||
|
||||
if ((acs_ch_list_all ||
|
||||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan)) &&
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
int_array_add_unique(freq_list, chan->freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
{
|
||||
struct drv_acs_params params;
|
||||
int ret, i, acs_ch_list_all = 0;
|
||||
u8 *channels = NULL;
|
||||
unsigned int num_channels = 0;
|
||||
struct hostapd_hw_modes *mode;
|
||||
int *freq_list = NULL;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
|
||||
return 0;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.hw_mode = hapd->iface->conf->hw_mode;
|
||||
|
||||
/*
|
||||
* If no chanlist config parameter is provided, include all enabled
|
||||
* channels of the selected hw_mode.
|
||||
*/
|
||||
if (!hapd->iface->conf->acs_ch_list.num)
|
||||
acs_ch_list_all = 1;
|
||||
|
||||
mode = hapd->iface->current_mode;
|
||||
if (mode) {
|
||||
channels = os_malloc(mode->num_channels);
|
||||
if (channels == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[i];
|
||||
if (!acs_ch_list_all &&
|
||||
!freq_range_list_includes(
|
||||
&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan))
|
||||
continue;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
|
||||
channels[num_channels++] = chan->chan;
|
||||
int_array_add_unique(&freq_list, chan->freq);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||
mode = &hapd->iface->hw_features[i];
|
||||
hostapd_get_hw_mode_any_channels(hapd, mode,
|
||||
acs_ch_list_all,
|
||||
&freq_list);
|
||||
}
|
||||
}
|
||||
|
||||
params.ch_list = channels;
|
||||
params.ch_list_len = num_channels;
|
||||
params.freq_list = freq_list;
|
||||
|
||||
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, ¶ms);
|
||||
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
|
||||
params.ch_width = 20;
|
||||
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
|
||||
params.ch_width = 40;
|
||||
|
||||
/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
|
||||
*/
|
||||
if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
|
||||
if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
params.ch_width = 80;
|
||||
else if (hapd->iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_160MHZ ||
|
||||
hapd->iface->conf->vht_oper_chwidth ==
|
||||
VHT_CHANWIDTH_80P80MHZ)
|
||||
params.ch_width = 160;
|
||||
}
|
||||
|
||||
ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms);
|
||||
os_free(channels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
|
||||
struct wpabuf *proberesp,
|
||||
struct wpabuf *assocresp);
|
||||
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
|
||||
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
|
||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
|
@ -193,14 +193,14 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
elems->supp_rates, elems->supp_rates_len,
|
||||
elems->ext_supp_rates, elems->ext_supp_rates_len);
|
||||
|
||||
if (elems->erp_info && elems->erp_info_len == 1)
|
||||
if (elems->erp_info)
|
||||
ap->erp = elems->erp_info[0];
|
||||
else
|
||||
ap->erp = -1;
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
if (elems->ds_params)
|
||||
ap->channel = elems->ds_params[0];
|
||||
else if (elems->ht_operation && elems->ht_operation_len >= 1)
|
||||
else if (elems->ht_operation)
|
||||
ap->channel = elems->ht_operation[0];
|
||||
else if (fi)
|
||||
ap->channel = fi->channel;
|
||||
@ -248,15 +248,12 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
void ap_list_timer(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_ctx;
|
||||
struct os_reltime now;
|
||||
struct ap_info *ap;
|
||||
int set_beacon = 0;
|
||||
|
||||
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||
|
||||
if (!iface->ap_list)
|
||||
return;
|
||||
|
||||
@ -305,13 +302,11 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
|
||||
int ap_list_init(struct hostapd_iface *iface)
|
||||
{
|
||||
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ap_list_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
eloop_cancel_timeout(ap_list_timer, iface, NULL);
|
||||
hostapd_free_aps(iface);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
#ifdef NEED_AP_MLME
|
||||
int ap_list_init(struct hostapd_iface *iface);
|
||||
void ap_list_deinit(struct hostapd_iface *iface);
|
||||
void ap_list_timer(struct hostapd_iface *iface);
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline int ap_list_init(struct hostapd_iface *iface)
|
||||
{
|
||||
@ -48,6 +49,10 @@ static inline int ap_list_init(struct hostapd_iface *iface)
|
||||
static inline void ap_list_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ap_list_timer(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#endif /* AP_LIST_H */
|
||||
|
@ -55,10 +55,11 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
{
|
||||
const struct hostapd_eap_user *eap_user;
|
||||
int i;
|
||||
int rv = -1;
|
||||
|
||||
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
|
||||
if (eap_user == NULL)
|
||||
return -1;
|
||||
goto out;
|
||||
|
||||
if (user == NULL)
|
||||
return 0;
|
||||
@ -72,7 +73,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
if (eap_user->password) {
|
||||
user->password = os_malloc(eap_user->password_len);
|
||||
if (user->password == NULL)
|
||||
return -1;
|
||||
goto out;
|
||||
os_memcpy(user->password, eap_user->password,
|
||||
eap_user->password_len);
|
||||
user->password_len = eap_user->password_len;
|
||||
@ -83,8 +84,13 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
user->ttls_auth = eap_user->ttls_auth;
|
||||
user->remediation = eap_user->remediation;
|
||||
user->accept_attr = eap_user->accept_attr;
|
||||
rv = 0;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (rv)
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@ -126,6 +132,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_HS20 */
|
||||
srv.erp = conf->eap_server_erp;
|
||||
srv.erp_domain = conf->erp_domain;
|
||||
srv.tls_session_lifetime = conf->tls_session_lifetime;
|
||||
|
||||
hapd->radius_srv = radius_server_init(&srv);
|
||||
if (hapd->radius_srv == NULL) {
|
||||
@ -145,9 +152,12 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
if (hapd->conf->eap_server &&
|
||||
(hapd->conf->ca_cert || hapd->conf->server_cert ||
|
||||
hapd->conf->private_key || hapd->conf->dh_file)) {
|
||||
struct tls_config conf;
|
||||
struct tls_connection_params params;
|
||||
|
||||
hapd->ssl_ctx = tls_init(NULL);
|
||||
os_memset(&conf, 0, sizeof(conf));
|
||||
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
hapd->ssl_ctx = tls_init(&conf);
|
||||
if (hapd->ssl_ctx == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
|
||||
authsrv_deinit(hapd);
|
||||
|
@ -360,7 +360,6 @@ static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
|
||||
|
||||
|
||||
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const struct ieee80211_mgmt *req,
|
||||
int is_p2p, size_t *resp_len)
|
||||
{
|
||||
@ -378,6 +377,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
if (hapd->p2p_probe_resp_ie)
|
||||
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies)
|
||||
buflen += wpabuf_len(hapd->iface->fst_ies);
|
||||
#endif /* CONFIG_FST */
|
||||
if (hapd->conf->vendor_elements)
|
||||
buflen += wpabuf_len(hapd->conf->vendor_elements);
|
||||
if (hapd->conf->vendor_vht) {
|
||||
@ -402,7 +405,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||
resp->u.probe_resp.capab_info =
|
||||
host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
|
||||
host_to_le16(hostapd_own_capab_info(hapd));
|
||||
|
||||
pos = resp->u.probe_resp.variable;
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
@ -450,6 +453,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
|
||||
&hapd->cs_c_off_proberesp);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
|
||||
wpabuf_len(hapd->iface->fst_ies));
|
||||
pos += wpabuf_len(hapd->iface->fst_ies);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos);
|
||||
@ -540,6 +552,102 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
void sta_track_expire(struct hostapd_iface *iface, int force)
|
||||
{
|
||||
struct os_reltime now;
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
if (!iface->num_sta_seen)
|
||||
return;
|
||||
|
||||
os_get_reltime(&now);
|
||||
while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
|
||||
list))) {
|
||||
if (!force &&
|
||||
!os_reltime_expired(&now, &info->last_seen,
|
||||
iface->conf->track_sta_max_age))
|
||||
break;
|
||||
force = 0;
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
|
||||
MACSTR, iface->bss[0]->conf->iface,
|
||||
MAC2STR(info->addr));
|
||||
dl_list_del(&info->list);
|
||||
iface->num_sta_seen--;
|
||||
os_free(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
|
||||
if (os_memcmp(addr, info->addr, ETH_ALEN) == 0)
|
||||
return info;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
info = sta_track_get(iface, addr);
|
||||
if (info) {
|
||||
/* Move the most recent entry to the end of the list */
|
||||
dl_list_del(&info->list);
|
||||
dl_list_add_tail(&iface->sta_seen, &info->list);
|
||||
os_get_reltime(&info->last_seen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add a new entry */
|
||||
info = os_zalloc(sizeof(*info));
|
||||
os_memcpy(info->addr, addr, ETH_ALEN);
|
||||
os_get_reltime(&info->last_seen);
|
||||
|
||||
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
|
||||
/* Expire oldest entry to make room for a new one */
|
||||
sta_track_expire(iface, 1);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
|
||||
MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
|
||||
dl_list_add_tail(&iface->sta_seen, &info->list);
|
||||
iface->num_sta_seen++;
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_data *
|
||||
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
|
||||
const char *ifname)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = iface->interfaces;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
struct hostapd_data *hapd = NULL;
|
||||
|
||||
iface = interfaces->iface[i];
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
if (os_strcmp(ifname, hapd->conf->iface) == 0)
|
||||
break;
|
||||
hapd = NULL;
|
||||
}
|
||||
|
||||
if (hapd && sta_track_get(iface, addr))
|
||||
return hapd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void handle_probe_req(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||
int ssi_signal)
|
||||
@ -548,7 +656,6 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
struct sta_info *sta = NULL;
|
||||
size_t i, resp_len;
|
||||
int noack;
|
||||
enum ssid_match_result res;
|
||||
@ -556,6 +663,8 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
ie = mgmt->u.probe_req.variable;
|
||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
|
||||
return;
|
||||
if (hapd->iconf->track_sta_max_num)
|
||||
sta_track_add(hapd->iface, mgmt->sa);
|
||||
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
|
||||
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
|
||||
@ -590,7 +699,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
* 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 &&
|
||||
if (elems.ds_params &&
|
||||
hapd->iface->current_mode &&
|
||||
(hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
|
||||
@ -635,8 +744,6 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
|
||||
elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
|
||||
@ -649,10 +756,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
|
||||
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
|
||||
elems.ssid_list, elems.ssid_list_len);
|
||||
if (res != NO_SSID_MATCH) {
|
||||
if (sta)
|
||||
sta->ssid_probe = &hapd->conf->ssid;
|
||||
} else {
|
||||
if (res == NO_SSID_MATCH) {
|
||||
if (!(mgmt->da[0] & 0x01)) {
|
||||
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
|
||||
" for foreign SSID '%s' (DA " MACSTR ")%s",
|
||||
@ -709,6 +813,18 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
/* TODO: verify that supp_rates contains at least one matching rate
|
||||
* with AP configuration */
|
||||
|
||||
if (hapd->conf->no_probe_resp_if_seen_on &&
|
||||
is_multicast_ether_addr(mgmt->da) &&
|
||||
is_multicast_ether_addr(mgmt->bssid) &&
|
||||
sta_track_seen_on(hapd->iface, mgmt->sa,
|
||||
hapd->conf->no_probe_resp_if_seen_on)) {
|
||||
wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
|
||||
" since STA has been seen on %s",
|
||||
hapd->conf->iface, MAC2STR(mgmt->sa),
|
||||
hapd->conf->no_probe_resp_if_seen_on);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->iconf->ignore_probe_probability > 0.0 &&
|
||||
drand48() < hapd->iconf->ignore_probe_probability) {
|
||||
@ -719,7 +835,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
|
||||
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
|
||||
&resp_len);
|
||||
if (resp == NULL)
|
||||
return;
|
||||
@ -774,7 +890,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
|
||||
"this");
|
||||
|
||||
/* Generate a Probe Response template for the non-P2P case */
|
||||
return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
|
||||
return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
@ -804,6 +920,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
if (hapd->p2p_beacon_ie)
|
||||
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies)
|
||||
tail_len += wpabuf_len(hapd->iface->fst_ies);
|
||||
#endif /* CONFIG_FST */
|
||||
if (hapd->conf->vendor_elements)
|
||||
tail_len += wpabuf_len(hapd->conf->vendor_elements);
|
||||
|
||||
@ -833,7 +953,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
host_to_le16(hapd->iconf->beacon_int);
|
||||
|
||||
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||
capab_info = hostapd_own_capab_info(hapd, NULL, 0);
|
||||
capab_info = hostapd_own_capab_info(hapd);
|
||||
head->u.beacon.capab_info = host_to_le16(capab_info);
|
||||
pos = &head->u.beacon.variable[0];
|
||||
|
||||
@ -902,6 +1022,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
|
||||
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
|
||||
&hapd->cs_c_off_beacon);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
|
||||
wpabuf_len(hapd->iface->fst_ies));
|
||||
tailpos += wpabuf_len(hapd->iface->fst_ies);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
|
||||
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
|
||||
@ -963,8 +1092,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
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;
|
||||
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
|
||||
(WPA_PROTO_WPA | WPA_PROTO_RSN))
|
||||
params->pairwise_ciphers = hapd->conf->wpa_pairwise |
|
||||
hapd->conf->rsn_pairwise;
|
||||
else if (hapd->conf->wpa & WPA_PROTO_RSN)
|
||||
params->pairwise_ciphers = hapd->conf->rsn_pairwise;
|
||||
else if (hapd->conf->wpa & WPA_PROTO_WPA)
|
||||
params->pairwise_ciphers = 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;
|
||||
|
@ -21,5 +21,10 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
|
||||
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
struct wpa_driver_ap_params *params);
|
||||
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
|
||||
void sta_track_expire(struct hostapd_iface *iface, int force);
|
||||
struct hostapd_data *
|
||||
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
|
||||
const char *ifname);
|
||||
|
||||
#endif /* BEACON_H */
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "fst/fst_ctrl_iface.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "wpa_auth.h"
|
||||
@ -153,6 +154,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
if (sta->vlan_id > 0) {
|
||||
res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
|
||||
sta->vlan_id);
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -199,7 +207,10 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
|
||||
ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
|
||||
ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,6 +122,20 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = first_chan_idx; i < mode->num_channels; i++) {
|
||||
if (mode->channels[i].freq == freq)
|
||||
return &mode->channels[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
int first_chan_idx, int num_chans,
|
||||
int skip_radar)
|
||||
@ -129,15 +143,15 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
struct hostapd_channel_data *first_chan, *chan;
|
||||
int i;
|
||||
|
||||
if (first_chan_idx + num_chans >= mode->num_channels)
|
||||
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)
|
||||
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
|
||||
first_chan_idx);
|
||||
if (!chan)
|
||||
return 0;
|
||||
|
||||
if (!dfs_channel_available(chan, skip_radar))
|
||||
@ -151,16 +165,10 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
static int is_in_chanlist(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan)
|
||||
{
|
||||
int *entry;
|
||||
|
||||
if (!iface->conf->chanlist)
|
||||
if (!iface->conf->acs_ch_list.num)
|
||||
return 1;
|
||||
|
||||
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
|
||||
if (*entry == chan->chan)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "crypto/random.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst.h"
|
||||
#include "wnm_ap.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
@ -42,10 +43,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
|
||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||
u8 *p = buf;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
|
||||
u16 reason = WLAN_REASON_UNSPECIFIED;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
const u8 *p2p_dev_addr = NULL;
|
||||
@ -58,8 +59,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
* running, so better make sure we stop processing such an
|
||||
* event here.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
|
||||
"no address");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"hostapd_notif_assoc: Skip event with no address");
|
||||
return -1;
|
||||
}
|
||||
random_add_randomness(addr, ETH_ALEN);
|
||||
@ -89,8 +90,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
} else {
|
||||
ie = NULL;
|
||||
ielen = 0;
|
||||
wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
|
||||
"(Re)AssocReq");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
@ -126,8 +127,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
#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 =
|
||||
@ -157,13 +156,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
sta->hs20_ie = NULL;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
wpabuf_free(sta->mb_ies);
|
||||
if (hapd->iface->fst)
|
||||
sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
|
||||
else
|
||||
sta->mb_ies = NULL;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
if (hapd->conf->wpa) {
|
||||
if (ie == NULL || ielen == 0) {
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state) {
|
||||
wpa_printf(MSG_DEBUG, "STA did not include "
|
||||
"WPA/RSN IE in (Re)Association "
|
||||
"Request - possible WPS use");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
|
||||
sta->flags |= WLAN_STA_MAYBE_WPS;
|
||||
goto skip_wpa_check;
|
||||
}
|
||||
@ -176,13 +182,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
|
||||
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
|
||||
struct wpabuf *wps;
|
||||
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wps = ieee802_11_vendor_ie_concat(ie, ielen,
|
||||
WPS_IE_VENDOR_TYPE);
|
||||
if (wps) {
|
||||
if (wps_is_20(wps)) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: STA "
|
||||
"supports WPS 2.0");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPS: STA supports WPS 2.0");
|
||||
sta->flags |= WLAN_STA_WPS2;
|
||||
}
|
||||
wpabuf_free(wps);
|
||||
@ -196,16 +203,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
sta->addr,
|
||||
p2p_dev_addr);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
|
||||
"machine");
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to initialize WPA state machine");
|
||||
return -1;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
ie, ielen,
|
||||
elems.mdie, elems.mdie_len);
|
||||
if (res != WPA_IE_OK) {
|
||||
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
|
||||
"rejected? (res %u)", res);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA/RSN information element rejected? (res %u)",
|
||||
res);
|
||||
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
|
||||
if (res == WPA_INVALID_GROUP) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
@ -248,14 +256,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
|
||||
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
|
||||
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
|
||||
p - buf);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -283,6 +289,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
} else if (hapd->conf->wps_state) {
|
||||
#ifdef CONFIG_WPS
|
||||
struct wpabuf *wps;
|
||||
|
||||
if (req_ies)
|
||||
wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
|
||||
WPS_IE_VENDOR_TYPE);
|
||||
@ -299,8 +306,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (wps) {
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
if (wps_is_20(wps)) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: STA supports "
|
||||
"WPS 2.0");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPS: STA supports WPS 2.0");
|
||||
sta->flags |= WLAN_STA_WPS2;
|
||||
}
|
||||
} else
|
||||
@ -322,8 +329,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
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");
|
||||
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,
|
||||
@ -395,8 +402,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
|
||||
* was running, so better make sure we stop processing such an
|
||||
* event here.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
|
||||
"with no address");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"hostapd_notif_disassoc: Skip event with no address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -405,8 +412,9 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Disassociation notification for "
|
||||
"unknown STA " MACSTR, MAC2STR(addr));
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Disassociation notification for unknown STA "
|
||||
MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -427,8 +435,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
|
||||
"missing ACKs");
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"disconnected due to excessive missing ACKs");
|
||||
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
if (sta)
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
@ -452,8 +460,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
channel = hostapd_hw_get_channel(hapd, freq);
|
||||
if (!channel) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING, "driver switched to "
|
||||
"bad channel!");
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"driver switched to bad channel!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -532,10 +540,9 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
u8 pri_channel, u8 sec_channel)
|
||||
struct acs_selected_channels *acs_res)
|
||||
{
|
||||
int channel;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
if (hapd->iconf->channel) {
|
||||
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
|
||||
@ -543,29 +550,73 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
|
||||
if (!hapd->iface->current_mode) {
|
||||
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||
struct hostapd_hw_modes *mode =
|
||||
&hapd->iface->hw_features[i];
|
||||
|
||||
channel = pri_channel;
|
||||
if (!channel) {
|
||||
if (mode->mode == acs_res->hw_mode) {
|
||||
hapd->iface->current_mode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hapd->iface->current_mode) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"driver selected to bad hw_mode");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
|
||||
|
||||
if (!acs_res->pri_channel) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"driver switched to bad channel");
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->iconf->channel = channel;
|
||||
hapd->iconf->channel = acs_res->pri_channel;
|
||||
hapd->iconf->acs = 1;
|
||||
|
||||
if (sec_channel == 0)
|
||||
if (acs_res->sec_channel == 0)
|
||||
hapd->iconf->secondary_channel = 0;
|
||||
else if (sec_channel < pri_channel)
|
||||
else if (acs_res->sec_channel < acs_res->pri_channel)
|
||||
hapd->iconf->secondary_channel = -1;
|
||||
else if (sec_channel > pri_channel)
|
||||
else if (acs_res->sec_channel > acs_res->pri_channel)
|
||||
hapd->iconf->secondary_channel = 1;
|
||||
else {
|
||||
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->iface->conf->ieee80211ac) {
|
||||
/* set defaults for backwards compatibility */
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
|
||||
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
if (acs_res->ch_width == 80) {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
|
||||
} else if (acs_res->ch_width == 160) {
|
||||
if (acs_res->vht_seg1_center_ch == 0) {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth =
|
||||
VHT_CHANWIDTH_160MHZ;
|
||||
} else {
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx =
|
||||
acs_res->vht_seg0_center_ch;
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx =
|
||||
acs_res->vht_seg1_center_ch;
|
||||
hapd->iconf->vht_oper_chwidth =
|
||||
VHT_CHANWIDTH_80P80MHZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = hostapd_acs_completed(hapd->iface, 0);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
@ -647,8 +698,8 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
|
||||
sta->addr, NULL);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
|
||||
"state machine");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Failed to initialize WPA state machine");
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
@ -683,7 +734,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
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",
|
||||
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
|
||||
mgmt->u.action.category, (int) plen);
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
@ -694,6 +745,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FT) {
|
||||
const u8 *payload = drv_mgmt->frame + 24 + 1;
|
||||
|
||||
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
@ -710,6 +762,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
|
||||
}
|
||||
#endif /* CONFIG_WNM */
|
||||
#ifdef CONFIG_FST
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
|
||||
fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -761,6 +820,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
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);
|
||||
@ -778,8 +838,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
|
||||
hapd = get_hapd_bssid(iface, bssid);
|
||||
if (hapd == NULL) {
|
||||
u16 fc;
|
||||
fc = le_to_host16(hdr->frame_control);
|
||||
u16 fc = le_to_host16(hdr->frame_control);
|
||||
|
||||
/*
|
||||
* Drop frames to unknown BSSIDs except for Beacon frames which
|
||||
@ -798,6 +857,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
|
||||
if (hapd == HAPD_BROADCAST) {
|
||||
size_t i;
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
/* if bss is set, driver will call this function for
|
||||
@ -824,6 +884,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
|
||||
size_t len, u16 stype, int ok)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) buf;
|
||||
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
|
||||
if (hapd == NULL || hapd == HAPD_BROADCAST)
|
||||
@ -837,6 +898,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
|
||||
static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (sta)
|
||||
return 0;
|
||||
|
||||
@ -863,11 +925,10 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
if ((sta = ap_get_sta(iface->bss[j], src))) {
|
||||
if (sta->flags & WLAN_STA_ASSOC) {
|
||||
hapd = iface->bss[j];
|
||||
break;
|
||||
}
|
||||
sta = ap_get_sta(iface->bss[j], src);
|
||||
if (sta && sta->flags & WLAN_STA_ASSOC) {
|
||||
hapd = iface->bss[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,7 +988,8 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
|
||||
if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
|
||||
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);
|
||||
@ -1061,6 +1123,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
data->rx_mgmt.frame_len >= 24) {
|
||||
const struct ieee80211_hdr *hdr;
|
||||
u16 fc;
|
||||
|
||||
hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
|
||||
fc = le_to_host16(hdr->frame_control);
|
||||
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
|
||||
@ -1248,9 +1311,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
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);
|
||||
hostapd_acs_channel_selected(hapd,
|
||||
&data->acs_selected_channels);
|
||||
break;
|
||||
#endif /* CONFIG_ACS */
|
||||
default:
|
||||
|
@ -138,8 +138,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
char id_str[256], cmd[300];
|
||||
size_t i;
|
||||
|
||||
if (identity_len >= sizeof(id_str))
|
||||
if (identity_len >= sizeof(id_str)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
|
||||
__func__, (int) identity_len,
|
||||
(int) (sizeof(id_str)));
|
||||
return NULL;
|
||||
}
|
||||
os_memcpy(id_str, identity, identity_len);
|
||||
id_str[identity_len] = '\0';
|
||||
for (i = 0; i < identity_len; i++) {
|
||||
@ -182,7 +186,9 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
|
||||
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
|
||||
SQLITE_OK) {
|
||||
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DB: Failed to complete SQL operation: %s db: %s",
|
||||
sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
|
||||
} else if (hapd->tmp_eap_user.next)
|
||||
user = &hapd->tmp_eap_user;
|
||||
|
||||
@ -192,8 +198,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
|
||||
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
|
||||
if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
|
||||
NULL) != SQLITE_OK) {
|
||||
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
|
||||
"operation");
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DB: Failed to complete SQL operation: %s db: %s",
|
||||
sqlite3_errmsg(db),
|
||||
hapd->conf->eap_user_sqlite);
|
||||
} else if (hapd->tmp_eap_user.next) {
|
||||
user = &hapd->tmp_eap_user;
|
||||
os_free(user->identity);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "eap_server/tncs.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "fst/fst.h"
|
||||
#include "hostapd.h"
|
||||
#include "authsrv.h"
|
||||
#include "sta_info.h"
|
||||
@ -179,6 +180,7 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
hapd = iface->bss[j];
|
||||
hapd->iconf = newconf;
|
||||
hapd->iconf->channel = oldconf->channel;
|
||||
hapd->iconf->acs = oldconf->acs;
|
||||
hapd->iconf->secondary_channel = oldconf->secondary_channel;
|
||||
hapd->iconf->ieee80211n = oldconf->ieee80211n;
|
||||
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
|
||||
@ -259,6 +261,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
{
|
||||
os_free(hapd->probereq_cb);
|
||||
hapd->probereq_cb = NULL;
|
||||
hapd->num_probereq_cb = 0;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
wpabuf_free(hapd->p2p_beacon_ie);
|
||||
@ -353,6 +356,22 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
static void sta_track_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
if (!iface->num_sta_seen)
|
||||
return;
|
||||
|
||||
while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
|
||||
list))) {
|
||||
dl_list_del(&info->list);
|
||||
iface->num_sta_seen--;
|
||||
os_free(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
|
||||
@ -368,6 +387,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
os_free(iface->basic_rates);
|
||||
iface->basic_rates = NULL;
|
||||
ap_list_deinit(iface);
|
||||
sta_track_deinit(iface);
|
||||
}
|
||||
|
||||
|
||||
@ -861,7 +881,7 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||
static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
{
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
|
||||
u8 ssid[SSID_MAX_LEN + 1];
|
||||
int ssid_len, set_ssid;
|
||||
char force_ifname[IFNAMSIZ];
|
||||
u8 if_addr[ETH_ALEN];
|
||||
@ -1363,6 +1383,132 @@ static int setup_interface2(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
|
||||
static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
return hapd->own_addr;
|
||||
}
|
||||
|
||||
|
||||
static void fst_hostapd_get_channel_info_cb(void *ctx,
|
||||
enum hostapd_hw_mode *hw_mode,
|
||||
u8 *channel)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
*hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
|
||||
}
|
||||
|
||||
|
||||
static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
if (hapd->iface->fst_ies != fst_ies) {
|
||||
hapd->iface->fst_ies = fst_ies;
|
||||
if (ieee802_11_set_beacon(hapd))
|
||||
wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
}
|
||||
|
||||
|
||||
static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
return sta ? sta->mb_ies : NULL;
|
||||
}
|
||||
|
||||
|
||||
static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
|
||||
const u8 *buf, size_t size)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (sta) {
|
||||
struct mb_ies_info info;
|
||||
|
||||
if (!mb_ies_info_by_ies(&info, buf, size)) {
|
||||
wpabuf_free(sta->mb_ies);
|
||||
sta->mb_ies = mb_ies_by_info(&info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
{
|
||||
struct sta_info *s = (struct sta_info *) *get_ctx;
|
||||
|
||||
if (mb_only) {
|
||||
for (; s && !s->mb_ies; s = s->next)
|
||||
;
|
||||
}
|
||||
|
||||
if (s) {
|
||||
*get_ctx = (struct fst_get_peer_ctx *) s->next;
|
||||
|
||||
return s->addr;
|
||||
}
|
||||
|
||||
*get_ctx = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const u8 * fst_hostapd_get_peer_first(void *ctx,
|
||||
struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
*get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
|
||||
|
||||
return fst_hostapd_get_sta(get_ctx, mb_only);
|
||||
}
|
||||
|
||||
|
||||
static const u8 * fst_hostapd_get_peer_next(void *ctx,
|
||||
struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
{
|
||||
return fst_hostapd_get_sta(get_ctx, mb_only);
|
||||
}
|
||||
|
||||
|
||||
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
struct fst_wpa_obj *iface_obj)
|
||||
{
|
||||
iface_obj->ctx = hapd;
|
||||
iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
|
||||
iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
|
||||
iface_obj->set_ies = fst_hostapd_set_ies_cb;
|
||||
iface_obj->send_action = fst_hostapd_send_action_cb;
|
||||
iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
|
||||
iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
|
||||
iface_obj->get_peer_first = fst_hostapd_get_peer_first;
|
||||
iface_obj->get_peer_next = fst_hostapd_get_peer_next;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_interface_complete - Complete interface setup
|
||||
*
|
||||
@ -1495,6 +1641,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
hostapd_tx_queue_params(iface);
|
||||
|
||||
ap_list_init(iface);
|
||||
dl_list_init(&iface->sta_seen);
|
||||
|
||||
hostapd_set_acl(hapd);
|
||||
|
||||
@ -1528,6 +1675,22 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
#ifdef NEED_AP_MLME
|
||||
dfs_offload:
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iconf->fst_cfg.group_id[0]) {
|
||||
struct fst_wpa_obj iface_obj;
|
||||
|
||||
fst_hostapd_fill_iface_obj(hapd, &iface_obj);
|
||||
iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
|
||||
&iface_obj, &hapd->iconf->fst_cfg);
|
||||
if (!iface->fst) {
|
||||
wpa_printf(MSG_ERROR, "Could not attach to FST %s",
|
||||
hapd->iconf->fst_cfg.group_id);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
|
||||
if (hapd->setup_complete_cb)
|
||||
@ -1544,6 +1707,12 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
wpa_printf(MSG_ERROR, "Interface initialization failed");
|
||||
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||
#ifdef CONFIG_FST
|
||||
if (iface->fst) {
|
||||
fst_detach(iface->fst);
|
||||
iface->fst = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error)
|
||||
eloop_terminate();
|
||||
return -1;
|
||||
@ -1643,6 +1812,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
|
||||
iface->wait_channel_update = 0;
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (iface->fst) {
|
||||
fst_detach(iface->fst);
|
||||
iface->fst = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
for (j = iface->num_bss - 1; j >= 0; j--)
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
}
|
||||
@ -2029,7 +2205,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
|
||||
|
||||
static struct hostapd_config *
|
||||
hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
|
||||
const char *ctrl_iface)
|
||||
const char *ctrl_iface, const char *driver)
|
||||
{
|
||||
struct hostapd_bss_config *bss;
|
||||
struct hostapd_config *conf;
|
||||
@ -2042,6 +2218,21 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver) {
|
||||
int j;
|
||||
|
||||
for (j = 0; wpa_drivers[j]; j++) {
|
||||
if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
|
||||
conf->driver = wpa_drivers[j];
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid/unknown driver '%s' - registering the default driver",
|
||||
driver);
|
||||
}
|
||||
|
||||
conf->driver = wpa_drivers[0];
|
||||
if (conf->driver == NULL) {
|
||||
wpa_printf(MSG_ERROR, "No driver wrappers registered!");
|
||||
@ -2049,6 +2240,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skip:
|
||||
bss = conf->last_bss = conf->bss[0];
|
||||
|
||||
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
|
||||
@ -2209,8 +2401,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
|
||||
if (conf && conf->bss)
|
||||
os_strlcpy(conf->bss[0]->iface, buf,
|
||||
sizeof(conf->bss[0]->iface));
|
||||
} else
|
||||
conf = hostapd_config_alloc(interfaces, buf, ptr);
|
||||
} else {
|
||||
char *driver = os_strchr(ptr, ' ');
|
||||
|
||||
if (driver)
|
||||
*driver++ = '\0';
|
||||
conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
|
||||
}
|
||||
|
||||
if (conf == NULL || conf->bss == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
|
||||
"for configuration", __func__);
|
||||
@ -2722,4 +2920,43 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
hostapd_enable_iface(iface);
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_data * hostapd_get_iface(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 hapd;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
ap_list_timer(iface);
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *hapd = iface->bss[i];
|
||||
|
||||
if (!hapd->started)
|
||||
continue;
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
hostapd_acl_expire(hapd);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ struct hapd_interfaces {
|
||||
|
||||
size_t count;
|
||||
int global_ctrl_sock;
|
||||
struct wpa_ctrl_dst *global_ctrl_dst;
|
||||
char *global_iface_path;
|
||||
char *global_iface_name;
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
@ -49,6 +50,9 @@ struct hapd_interfaces {
|
||||
struct hostapd_iface **iface;
|
||||
|
||||
size_t terminate_on_error;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
struct dynamic_iface *vlan_priv;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@ -265,6 +269,7 @@ struct hostapd_data {
|
||||
/** Key used for generating SAE anti-clogging tokens */
|
||||
u8 sae_token_key[8];
|
||||
struct os_reltime last_sae_token_key_update;
|
||||
int dot11RSNASAERetransPeriod; /* msec */
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
@ -276,6 +281,12 @@ struct hostapd_data {
|
||||
};
|
||||
|
||||
|
||||
struct hostapd_sta_info {
|
||||
struct dl_list list;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct os_reltime last_seen;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_iface - hostapd per-interface data structure
|
||||
*/
|
||||
@ -305,6 +316,10 @@ struct hostapd_iface {
|
||||
|
||||
unsigned int wait_channel_update:1;
|
||||
unsigned int cac_started:1;
|
||||
#ifdef CONFIG_FST
|
||||
struct fst_iface *fst;
|
||||
const struct wpabuf *fst_ies;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
/*
|
||||
* When set, indicates that the driver will handle the AP
|
||||
@ -400,6 +415,9 @@ struct hostapd_iface {
|
||||
|
||||
void (*scan_cb)(struct hostapd_iface *iface);
|
||||
int num_ht40_scan_tries;
|
||||
|
||||
struct dl_list sta_seen; /* struct hostapd_sta_info */
|
||||
unsigned int num_sta_seen;
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -437,6 +455,7 @@ 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);
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
@ -464,4 +483,12 @@ const struct hostapd_eap_user *
|
||||
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
|
||||
size_t identity_len, int phase2);
|
||||
|
||||
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
|
||||
const char *ifname);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
struct fst_wpa_obj *iface_obj);
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#endif /* HOSTAPD_H */
|
||||
|
@ -260,8 +260,14 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
|
||||
|
||||
res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
|
||||
|
||||
if (res == 2)
|
||||
ieee80211n_switch_pri_sec(iface);
|
||||
if (res == 2) {
|
||||
if (iface->conf->no_pri_sec_switch) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Cannot switch PRI/SEC channels due to local constraint");
|
||||
} else {
|
||||
ieee80211n_switch_pri_sec(iface);
|
||||
}
|
||||
}
|
||||
|
||||
return !!res;
|
||||
}
|
||||
@ -347,8 +353,13 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
|
||||
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;
|
||||
/*
|
||||
* Note: Need to find the PRI channel also in cases where the affected
|
||||
* channel is the SEC channel of a 40 MHz BSS, so need to include the
|
||||
* scanning coverage here to be 40 MHz from the center frequency.
|
||||
*/
|
||||
affected_start = (pri_freq + sec_freq) / 2 - 40;
|
||||
affected_end = (pri_freq + sec_freq) / 2 + 40;
|
||||
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
|
||||
affected_start, affected_end);
|
||||
|
||||
@ -510,7 +521,11 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
|
||||
/*
|
||||
* Driver ACS chosen channel may not be HT40 due to internal driver
|
||||
* restrictions.
|
||||
*/
|
||||
if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
|
||||
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
|
||||
wpa_printf(MSG_ERROR, "Driver does not support configured "
|
||||
"HT capability [HT40*]");
|
||||
@ -717,6 +732,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
int ret;
|
||||
if (!iface->conf->ieee80211n)
|
||||
return 0;
|
||||
|
||||
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B &&
|
||||
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G &&
|
||||
(iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Disable HT capability [DSSS_CCK-40] on 5 GHz band");
|
||||
iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ;
|
||||
}
|
||||
|
||||
if (!ieee80211n_supported_ht_capab(iface))
|
||||
return -1;
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
@ -740,6 +764,9 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
if (!iface->current_mode)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
if (chan->chan != channel)
|
||||
@ -801,6 +828,12 @@ hostapd_check_chans(struct hostapd_iface *iface)
|
||||
|
||||
static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
if (!iface->current_mode) {
|
||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Hardware does not support configured mode");
|
||||
return;
|
||||
}
|
||||
hostapd_logger(iface->bss[0], NULL,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
@ -891,14 +924,18 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
if (iface->current_mode == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Hardware does not support configured "
|
||||
"mode");
|
||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Hardware does not support configured mode "
|
||||
"(%d) (hw_mode in hostapd.conf)",
|
||||
(int) iface->conf->hw_mode);
|
||||
return -2;
|
||||
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
|
||||
!(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
|
||||
{
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Hardware does not support configured mode");
|
||||
hostapd_logger(iface->bss[0], NULL,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)",
|
||||
(int) iface->conf->hw_mode);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (hostapd_check_chans(iface)) {
|
||||
|
@ -36,6 +36,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
{
|
||||
return -100;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst.h"
|
||||
#include "hostapd.h"
|
||||
#include "beacon.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
@ -38,6 +39,7 @@
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wnm_ap.h"
|
||||
#include "hw_features.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
@ -132,8 +134,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
|
||||
}
|
||||
|
||||
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int probe)
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
|
||||
{
|
||||
int capab = WLAN_CAPABILITY_ESS;
|
||||
int privacy;
|
||||
@ -166,20 +167,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
privacy = 1;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
if (sta) {
|
||||
int policy, def_klen;
|
||||
if (probe && sta->ssid_probe) {
|
||||
policy = sta->ssid_probe->security_policy;
|
||||
def_klen = sta->ssid_probe->wep.default_len;
|
||||
} else {
|
||||
policy = sta->ssid->security_policy;
|
||||
def_klen = sta->ssid->wep.default_len;
|
||||
}
|
||||
privacy = policy != SECURITY_PLAINTEXT;
|
||||
if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
|
||||
privacy = 0;
|
||||
}
|
||||
|
||||
if (privacy)
|
||||
capab |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
@ -206,6 +193,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_RC4
|
||||
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 auth_transaction, const u8 *challenge,
|
||||
int iswep)
|
||||
@ -259,6 +247,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
|
||||
|
||||
static void send_auth_reply(struct hostapd_data *hapd,
|
||||
@ -328,7 +317,6 @@ 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 */
|
||||
|
||||
|
||||
@ -511,12 +499,14 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
|
||||
switch (sta->sae->state) {
|
||||
case SAE_COMMITTED:
|
||||
ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
|
||||
eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
|
||||
eloop_register_timeout(0,
|
||||
hapd->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,
|
||||
eloop_register_timeout(0,
|
||||
hapd->dot11RSNASAERetransPeriod * 1000,
|
||||
auth_sae_retransmit_timer, hapd, sta);
|
||||
break;
|
||||
default:
|
||||
@ -542,7 +532,7 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
|
||||
return;
|
||||
|
||||
eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
|
||||
eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
|
||||
eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
|
||||
auth_sae_retransmit_timer, hapd, sta);
|
||||
}
|
||||
|
||||
@ -624,7 +614,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
sta->sae->sync++;
|
||||
|
||||
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
|
||||
ret = auth_sae_send_commit(hapd, sta, bssid, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -784,6 +774,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
((const u8 *) mgmt) + len -
|
||||
mgmt->u.auth.variable, &token,
|
||||
&token_len, hapd->conf->sae_groups);
|
||||
if (resp == SAE_SILENTLY_DISCARD) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: Drop commit message from " MACSTR " due to reflection attack",
|
||||
MAC2STR(sta->addr));
|
||||
return;
|
||||
}
|
||||
if (token && check_sae_token(hapd, sta->addr, token, token_len)
|
||||
< 0) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
|
||||
@ -934,6 +930,16 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
challenge ? " challenge" : "",
|
||||
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
|
||||
|
||||
#ifdef CONFIG_NO_RC4
|
||||
if (auth_alg == WLAN_AUTH_SHARED_KEY) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Unsupported authentication algorithm (%d)",
|
||||
auth_alg);
|
||||
resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
|
||||
if (hapd->tkip_countermeasures) {
|
||||
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
|
||||
goto fail;
|
||||
@ -972,6 +978,61 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hapd->conf->no_auth_if_seen_on) {
|
||||
struct hostapd_data *other;
|
||||
|
||||
other = sta_track_seen_on(hapd->iface, mgmt->sa,
|
||||
hapd->conf->no_auth_if_seen_on);
|
||||
if (other) {
|
||||
u8 *pos;
|
||||
u32 info;
|
||||
u8 op_class, channel, phytype;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
|
||||
MACSTR " since STA has been seen on %s",
|
||||
hapd->conf->iface, MAC2STR(mgmt->sa),
|
||||
hapd->conf->no_auth_if_seen_on);
|
||||
|
||||
resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
|
||||
pos = &resp_ies[0];
|
||||
*pos++ = WLAN_EID_NEIGHBOR_REPORT;
|
||||
*pos++ = 13;
|
||||
os_memcpy(pos, other->own_addr, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
info = 0; /* TODO: BSSID Information */
|
||||
WPA_PUT_LE32(pos, info);
|
||||
pos += 4;
|
||||
if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
|
||||
phytype = 8; /* dmg */
|
||||
else if (other->iconf->ieee80211ac)
|
||||
phytype = 9; /* vht */
|
||||
else if (other->iconf->ieee80211n)
|
||||
phytype = 7; /* ht */
|
||||
else if (other->iconf->hw_mode ==
|
||||
HOSTAPD_MODE_IEEE80211A)
|
||||
phytype = 4; /* ofdm */
|
||||
else if (other->iconf->hw_mode ==
|
||||
HOSTAPD_MODE_IEEE80211G)
|
||||
phytype = 6; /* erp */
|
||||
else
|
||||
phytype = 5; /* hrdsss */
|
||||
if (ieee80211_freq_to_channel_ext(
|
||||
hostapd_hw_get_freq(other,
|
||||
other->iconf->channel),
|
||||
other->iconf->secondary_channel,
|
||||
other->iconf->ieee80211ac,
|
||||
&op_class, &channel) == NUM_HOSTAPD_MODES) {
|
||||
op_class = 0;
|
||||
channel = other->iconf->channel;
|
||||
}
|
||||
*pos++ = op_class;
|
||||
*pos++ = channel;
|
||||
*pos++ = phytype;
|
||||
resp_ies_len = pos - &resp_ies[0];
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
|
||||
&session_timeout,
|
||||
&acct_interim_interval, &vlan_id,
|
||||
@ -1081,6 +1142,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
sta->auth_alg = WLAN_AUTH_OPEN;
|
||||
mlme_authenticate_indication(hapd, sta);
|
||||
break;
|
||||
#ifndef CONFIG_NO_RC4
|
||||
case WLAN_AUTH_SHARED_KEY:
|
||||
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
|
||||
fc & WLAN_FC_ISWEP);
|
||||
@ -1094,6 +1156,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
case WLAN_AUTH_FT:
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
@ -1297,8 +1360,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
|
||||
elems.ht_capabilities_len);
|
||||
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
|
||||
@ -1311,14 +1373,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
|
||||
elems.vht_capabilities_len);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
if (hapd->iconf->ieee80211ac) {
|
||||
resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
|
||||
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;
|
||||
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)) {
|
||||
@ -1546,6 +1609,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
sta->hs20_ie = NULL;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
wpabuf_free(sta->mb_ies);
|
||||
if (hapd->iface->fst)
|
||||
sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
|
||||
else
|
||||
sta->mb_ies = NULL;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1594,7 +1665,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
send_len = IEEE80211_HDRLEN;
|
||||
send_len += sizeof(reply->u.assoc_resp);
|
||||
reply->u.assoc_resp.capab_info =
|
||||
host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
|
||||
host_to_le16(hostapd_own_capab_info(hapd));
|
||||
reply->u.assoc_resp.status_code = host_to_le16(status_code);
|
||||
reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
|
||||
/* Supported rates */
|
||||
@ -1634,6 +1705,14 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (sta->qos_map_enabled)
|
||||
p = hostapd_eid_qos_map_set(hapd, p);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
|
||||
wpabuf_len(hapd->iface->fst_ies));
|
||||
p += wpabuf_len(hapd->iface->fst_ies);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
|
||||
p = hostapd_eid_vendor_vht(hapd, p);
|
||||
@ -2112,10 +2191,20 @@ static int handle_action(struct hostapd_data *hapd,
|
||||
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
|
||||
return 1;
|
||||
#endif /* CONFIG_WNM */
|
||||
#ifdef CONFIG_FST
|
||||
case WLAN_ACTION_FST:
|
||||
if (hapd->iface->fst)
|
||||
fst_rx_action(hapd->iface->fst, mgmt, len);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FST: Ignore FST Action frame - no FST attached");
|
||||
return 1;
|
||||
#endif /* CONFIG_FST */
|
||||
case WLAN_ACTION_PUBLIC:
|
||||
case WLAN_ACTION_PROTECTED_DUAL:
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (mgmt->u.action.u.public_action.action ==
|
||||
if (len >= IEEE80211_HDRLEN + 2 &&
|
||||
mgmt->u.action.u.public_action.action ==
|
||||
WLAN_PA_20_40_BSS_COEX) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HT20/40 coex mgmt frame received from STA "
|
||||
@ -2248,6 +2337,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->iconf->track_sta_max_num)
|
||||
sta_track_add(hapd->iface, mgmt->sa);
|
||||
|
||||
switch (stype) {
|
||||
case WLAN_FC_STYPE_AUTH:
|
||||
wpa_printf(MSG_DEBUG, "mgmt::auth");
|
||||
@ -2335,7 +2427,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
|
||||
char *ifname_wds)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_ssid *ssid = sta->ssid;
|
||||
struct hostapd_ssid *ssid = &hapd->conf->ssid;
|
||||
|
||||
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
|
||||
return;
|
||||
@ -2473,11 +2565,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||
* so bind it to the selected VLAN interface now, since the
|
||||
* interface selection is not going to change anymore.
|
||||
*/
|
||||
if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
|
||||
if (ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
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)
|
||||
if (ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ struct hostapd_data;
|
||||
struct sta_info;
|
||||
struct hostapd_frame_info;
|
||||
struct ieee80211_ht_capabilities;
|
||||
struct ieee80211_vht_capabilities;
|
||||
struct ieee80211_mgmt;
|
||||
|
||||
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
@ -40,8 +41,7 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
|
||||
return 0;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int probe);
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd);
|
||||
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);
|
||||
@ -62,7 +62,7 @@ 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);
|
||||
const u8 *ht_capab);
|
||||
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ie, size_t len);
|
||||
|
||||
@ -70,7 +70,7 @@ 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);
|
||||
const u8 *vht_capab);
|
||||
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,
|
||||
|
@ -399,19 +399,15 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
|
||||
|
||||
/**
|
||||
* hostapd_acl_expire - ACL cache expiration callback
|
||||
* @eloop_ctx: struct hostapd_data *
|
||||
* @timeout_ctx: Not used
|
||||
* @hapd: struct hostapd_data *
|
||||
*/
|
||||
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
|
||||
void hostapd_acl_expire(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct os_reltime now;
|
||||
|
||||
os_get_reltime(&now);
|
||||
hostapd_acl_expire_cache(hapd, &now);
|
||||
hostapd_acl_expire_queries(hapd, &now);
|
||||
|
||||
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -561,6 +557,19 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
|
||||
!cache->psk)
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (cache->vlan_id &&
|
||||
!hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
|
||||
hostapd_logger(hapd, query->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN ID %d received from RADIUS server",
|
||||
cache->vlan_id);
|
||||
cache->vlan_id = 0;
|
||||
}
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!cache->vlan_id)
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
} else
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
cache->next = hapd->acl_cache;
|
||||
@ -602,8 +611,6 @@ int hostapd_acl_init(struct hostapd_data *hapd)
|
||||
if (radius_client_register(hapd->radius, RADIUS_AUTH,
|
||||
hostapd_acl_recv_radius, hapd))
|
||||
return -1;
|
||||
|
||||
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
return 0;
|
||||
@ -619,8 +626,6 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||
struct hostapd_acl_query_data *query, *prev;
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
|
||||
|
||||
hostapd_acl_cache_free(hapd->acl_cache);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
@ -24,5 +24,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
|
||||
void hostapd_acl_expire(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* IEEE802_11_AUTH_H */
|
||||
|
@ -209,7 +209,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
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 is_ht40_allowed = 1;
|
||||
int i;
|
||||
const u8 *start = (const u8 *) mgmt;
|
||||
const u8 *data = start + IEEE80211_HDRLEN + 2;
|
||||
@ -242,7 +242,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"20 MHz BSS width request bit is set in BSS coexistence information field");
|
||||
is_ht_allowed = 0;
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
|
||||
@ -250,7 +250,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"40 MHz intolerant bit is set in BSS coexistence information field");
|
||||
is_ht_allowed = 0;
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
if (start + len - data >= 3 &&
|
||||
@ -276,13 +276,13 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"20_40_INTOLERANT channel %d reported",
|
||||
chan);
|
||||
is_ht_allowed = 0;
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
|
||||
is_ht_allowed, iface->num_sta_ht40_intolerant);
|
||||
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
|
||||
is_ht40_allowed, iface->num_sta_ht40_intolerant);
|
||||
|
||||
if (!is_ht_allowed &&
|
||||
if (!is_ht40_allowed &&
|
||||
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
|
||||
if (iface->conf->secondary_channel) {
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
@ -310,12 +310,15 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
|
||||
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab, size_t ht_capab_len)
|
||||
const u8 *ht_capab)
|
||||
{
|
||||
/* Disable HT caps for STAs associated to no-HT BSSes. */
|
||||
/*
|
||||
* Disable HT caps for STAs associated to no-HT BSSes, or for stations
|
||||
* that did not specify a valid WMM IE in the (Re)Association Request
|
||||
* frame.
|
||||
*/
|
||||
if (!ht_capab ||
|
||||
ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
|
||||
hapd->conf->disable_11n) {
|
||||
!(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
|
||||
sta->flags &= ~WLAN_STA_HT;
|
||||
os_free(sta->ht_capabilities);
|
||||
sta->ht_capabilities = NULL;
|
||||
|
@ -132,11 +132,10 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
|
||||
|
||||
|
||||
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_capab, size_t vht_capab_len)
|
||||
const u8 *vht_capab)
|
||||
{
|
||||
/* 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 ||
|
||||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
|
||||
sta->flags &= ~WLAN_STA_VHT;
|
||||
|
@ -125,6 +125,9 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_FIPS
|
||||
#ifndef CONFIG_NO_RC4
|
||||
|
||||
static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
int idx, int broadcast,
|
||||
@ -204,7 +207,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
static 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;
|
||||
@ -259,6 +262,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_FIPS */
|
||||
|
||||
|
||||
const char *radius_mode_txt(struct hostapd_data *hapd)
|
||||
{
|
||||
@ -346,7 +352,8 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ?
|
||||
suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
|
||||
hapd->conf->osen) ?
|
||||
WPA_PROTO_RSN : WPA_PROTO_WPA,
|
||||
hapd->conf->wpa_group);
|
||||
if (!hostapd_config_get_radius_attr(req_attr,
|
||||
@ -453,7 +460,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
if (hapd->conf->wpa && sta->wpa_sm &&
|
||||
if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
|
||||
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
|
||||
return -1;
|
||||
|
||||
@ -599,7 +606,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eap && !radius_msg_add_eap(msg, eap, len)) {
|
||||
if (!radius_msg_add_eap(msg, eap, len)) {
|
||||
wpa_printf(MSG_INFO, "Could not add EAP-Message");
|
||||
goto fail;
|
||||
}
|
||||
@ -1108,8 +1115,6 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
|
||||
if (pmksa) {
|
||||
int old_vlanid;
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
|
||||
@ -1123,11 +1128,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
old_vlanid = sta->vlan_id;
|
||||
pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
|
||||
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
sta->vlan_id = 0;
|
||||
ap_sta_bind_vlan(hapd, sta, old_vlanid);
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
} else {
|
||||
if (reassoc) {
|
||||
/*
|
||||
@ -1290,7 +1292,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct radius_msg *msg)
|
||||
{
|
||||
u8 *class;
|
||||
u8 *attr_class;
|
||||
size_t class_len;
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
int count, i;
|
||||
@ -1312,12 +1314,12 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
|
||||
|
||||
nclass_count = 0;
|
||||
|
||||
class = NULL;
|
||||
attr_class = NULL;
|
||||
for (i = 0; i < count; i++) {
|
||||
do {
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
|
||||
&class, &class_len,
|
||||
class) < 0) {
|
||||
&attr_class, &class_len,
|
||||
attr_class) < 0) {
|
||||
i = count;
|
||||
break;
|
||||
}
|
||||
@ -1327,7 +1329,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
|
||||
if (nclass[nclass_count].data == NULL)
|
||||
break;
|
||||
|
||||
os_memcpy(nclass[nclass_count].data, class, class_len);
|
||||
os_memcpy(nclass[nclass_count].data, attr_class, class_len);
|
||||
nclass[nclass_count].len = class_len;
|
||||
nclass_count++;
|
||||
}
|
||||
@ -1590,7 +1592,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct hostapd_data *hapd = data;
|
||||
struct sta_info *sta;
|
||||
u32 session_timeout = 0, termination_action, acct_interim_interval;
|
||||
int session_timeout_set, old_vlanid = 0;
|
||||
int session_timeout_set, vlan_id = 0;
|
||||
struct eapol_state_machine *sm;
|
||||
int override_eapReq = 0;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
@ -1657,20 +1659,27 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
|
||||
switch (hdr->code) {
|
||||
case RADIUS_CODE_ACCESS_ACCEPT:
|
||||
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
sta->vlan_id = 0;
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
vlan_id = 0;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
else {
|
||||
old_vlanid = sta->vlan_id;
|
||||
sta->vlan_id = radius_msg_get_vlanid(msg);
|
||||
}
|
||||
if (sta->vlan_id > 0 &&
|
||||
hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
|
||||
else
|
||||
vlan_id = radius_msg_get_vlanid(msg);
|
||||
if (vlan_id > 0 &&
|
||||
hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"VLAN ID %d", sta->vlan_id);
|
||||
} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
|
||||
"VLAN ID %d", vlan_id);
|
||||
} else if (vlan_id > 0) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN ID %d received from RADIUS server",
|
||||
vlan_id);
|
||||
break;
|
||||
} else if (hapd->conf->ssid.dynamic_vlan ==
|
||||
DYNAMIC_VLAN_REQUIRED) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE8021X,
|
||||
@ -1681,7 +1690,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
|
||||
sta->vlan_id = vlan_id;
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
break;
|
||||
|
||||
sta->session_timeout_set = !!session_timeout_set;
|
||||
@ -1926,10 +1937,11 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
|
||||
struct hostapd_data *hapd = ctx;
|
||||
const struct hostapd_eap_user *eap_user;
|
||||
int i;
|
||||
int rv = -1;
|
||||
|
||||
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
|
||||
if (eap_user == NULL)
|
||||
return -1;
|
||||
goto out;
|
||||
|
||||
os_memset(user, 0, sizeof(*user));
|
||||
user->phase2 = phase2;
|
||||
@ -1941,7 +1953,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
|
||||
if (eap_user->password) {
|
||||
user->password = os_malloc(eap_user->password_len);
|
||||
if (user->password == NULL)
|
||||
return -1;
|
||||
goto out;
|
||||
os_memcpy(user->password, eap_user->password,
|
||||
eap_user->password_len);
|
||||
user->password_len = eap_user->password_len;
|
||||
@ -1951,8 +1963,13 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
|
||||
user->macacl = eap_user->macacl;
|
||||
user->ttls_auth = eap_user->ttls_auth;
|
||||
user->remediation = eap_user->remediation;
|
||||
rv = 0;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (rv)
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@ -2012,9 +2029,13 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
|
||||
|
||||
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
|
||||
{
|
||||
#ifndef CONFIG_FIPS
|
||||
#ifndef CONFIG_NO_RC4
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = sta_ctx;
|
||||
ieee802_1x_tx_key(hapd, sta);
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_FIPS */
|
||||
}
|
||||
|
||||
|
||||
@ -2085,6 +2106,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
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.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
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;
|
||||
@ -2332,9 +2354,9 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
|
||||
}
|
||||
|
||||
|
||||
static const char * bool_txt(Boolean bool)
|
||||
static const char * bool_txt(Boolean val)
|
||||
{
|
||||
return bool ? "TRUE" : "FALSE";
|
||||
return val ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,7 +23,6 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct sta_info *sta);
|
||||
|
||||
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
|
@ -81,12 +81,24 @@ static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
|
||||
}
|
||||
|
||||
|
||||
static void ucast_to_stas(struct hostapd_data *hapd, const u8 *buf, size_t len)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 in6_addr saddr;
|
||||
struct sta_info *sta;
|
||||
int res;
|
||||
char addrtxt[INET6_ADDRSTRLEN + 1];
|
||||
@ -101,25 +113,30 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
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)) {
|
||||
/*
|
||||
* IPv6 header may not be 32-bit aligned in the buffer, so use
|
||||
* a local copy to avoid unaligned reads.
|
||||
*/
|
||||
os_memcpy(&saddr, &msg->ipv6h.ip6_src, sizeof(saddr));
|
||||
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))
|
||||
if (sta_has_ip6addr(sta, &saddr))
|
||||
return;
|
||||
|
||||
if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
|
||||
== NULL)
|
||||
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,
|
||||
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,
|
||||
@ -128,21 +145,17 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta_ip6addr_add(sta, saddr))
|
||||
if (sta_ip6addr_add(sta, &saddr))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ROUTER_ADVERTISEMENT:
|
||||
if (!hapd->conf->disable_dgaf)
|
||||
return;
|
||||
/* fall through */
|
||||
if (hapd->conf->disable_dgaf)
|
||||
ucast_to_stas(hapd, buf, len);
|
||||
break;
|
||||
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);
|
||||
}
|
||||
if (hapd->conf->na_mcast_to_ucast)
|
||||
ucast_to_stas(hapd, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "fst/fst.h"
|
||||
#include "hostapd.h"
|
||||
#include "accounting.h"
|
||||
#include "ieee802_1x.h"
|
||||
@ -171,6 +172,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id_bound) {
|
||||
/*
|
||||
* Need to remove the STA entry before potentially removing the
|
||||
* VLAN.
|
||||
*/
|
||||
if (hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
ap_sta_list_del(hapd, sta);
|
||||
|
||||
@ -283,6 +297,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
wpabuf_free(sta->wps_ie);
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
wpabuf_free(sta->hs20_ie);
|
||||
#ifdef CONFIG_FST
|
||||
wpabuf_free(sta->mb_ies);
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
os_free(sta->ht_capabilities);
|
||||
os_free(sta->vht_capabilities);
|
||||
@ -619,7 +636,6 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
hapd->sta_list = sta;
|
||||
hapd->num_sta++;
|
||||
ap_sta_hash_add(hapd, sta);
|
||||
sta->ssid = &hapd->conf->ssid;
|
||||
ap_sta_remove_in_other_bss(hapd, sta);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
dl_list_init(&sta->ip6addr);
|
||||
@ -768,26 +784,19 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int old_vlanid)
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
const char *iface;
|
||||
struct hostapd_vlan *vlan = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do not proceed furthur if the vlan id remains same. We do not want
|
||||
* duplicate dynamic vlan entries.
|
||||
*/
|
||||
if (sta->vlan_id == old_vlanid)
|
||||
return 0;
|
||||
int old_vlanid = sta->vlan_id_bound;
|
||||
|
||||
iface = hapd->conf->iface;
|
||||
if (sta->ssid->vlan[0])
|
||||
iface = sta->ssid->vlan;
|
||||
if (hapd->conf->ssid.vlan[0])
|
||||
iface = hapd->conf->ssid.vlan;
|
||||
|
||||
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
sta->vlan_id = 0;
|
||||
else if (sta->vlan_id > 0) {
|
||||
struct hostapd_vlan *wildcard_vlan = NULL;
|
||||
@ -805,6 +814,14 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
iface = vlan->ifname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not increment ref counters if the VLAN ID remains same, but do
|
||||
* not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
|
||||
* have been called before.
|
||||
*/
|
||||
if (sta->vlan_id == old_vlanid)
|
||||
goto skip_counting;
|
||||
|
||||
if (sta->vlan_id > 0 && vlan == NULL) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
|
||||
@ -825,7 +842,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
iface = vlan->ifname;
|
||||
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
@ -838,7 +855,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
|
||||
"interface '%s'", iface);
|
||||
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
|
||||
if (sta->vlan_id > 0) {
|
||||
if (vlan->dynamic_vlan > 0) {
|
||||
vlan->dynamic_vlan++;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
@ -852,7 +869,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
* configuration for the case where hostapd did not yet know
|
||||
* which keys are to be used when the interface was added.
|
||||
*/
|
||||
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
@ -862,6 +879,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
}
|
||||
|
||||
/* ref counters have been increased, so mark the station */
|
||||
sta->vlan_id_bound = sta->vlan_id;
|
||||
|
||||
skip_counting:
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
|
||||
"'%s'", iface);
|
||||
@ -876,10 +897,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *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)
|
||||
if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
|
||||
vlan_remove_dynamic(hapd, old_vlanid);
|
||||
done:
|
||||
|
||||
return ret;
|
||||
#else /* CONFIG_NO_VLAN */
|
||||
@ -1043,6 +1064,16 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
|
||||
AP_STA_DISCONNECTED "%s", buf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst) {
|
||||
if (authorized)
|
||||
fst_notify_peer_connected(hapd->iface->fst, sta->addr);
|
||||
else
|
||||
fst_notify_peer_disconnected(hapd->iface->fst,
|
||||
sta->addr);
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,10 +117,8 @@ struct sta_info {
|
||||
struct wpa_state_machine *wpa_sm;
|
||||
struct rsn_preauth_interface *preauth_iface;
|
||||
|
||||
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
|
||||
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
|
||||
|
||||
int vlan_id;
|
||||
int vlan_id; /* 0: none, >0: VID */
|
||||
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
|
||||
/* PSKs from RADIUS authentication server */
|
||||
struct hostapd_sta_wpa_psk_short *psk;
|
||||
|
||||
@ -155,6 +153,9 @@ struct sta_info {
|
||||
struct wpabuf *hs20_deauth_req;
|
||||
char *hs20_session_info_url;
|
||||
int hs20_disassoc_timer;
|
||||
#ifdef CONFIG_FST
|
||||
struct wpabuf *mb_ies; /* MB IEs from (Re)Association Request */
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
struct os_reltime connected_time;
|
||||
|
||||
@ -218,8 +219,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *ctx);
|
||||
#endif /* CONFIG_WPS */
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int old_vlanid);
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "fst/fst.h"
|
||||
#include "sta_info.h"
|
||||
#include "hostapd.h"
|
||||
|
||||
@ -55,10 +56,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
|
||||
ohapd = iface->bss[j];
|
||||
if (ohapd == data->hapd)
|
||||
continue;
|
||||
#ifdef CONFIG_FST
|
||||
/* Don't prune STAs belong to same FST */
|
||||
if (ohapd->iface->fst &&
|
||||
data->hapd->iface->fst &&
|
||||
fst_are_ifaces_aggregated(ohapd->iface->fst,
|
||||
data->hapd->iface->fst))
|
||||
continue;
|
||||
#endif /* CONFIG_FST */
|
||||
osta = ap_get_sta(ohapd, data->addr);
|
||||
if (!osta)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
|
||||
ohapd->conf->iface, MAC2STR(osta->addr));
|
||||
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,13 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "hostapd.h"
|
||||
@ -20,12 +27,6 @@
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "drivers/priv_netlink.h"
|
||||
#include "utils/eloop.h"
|
||||
|
||||
@ -34,6 +35,90 @@ struct full_dynamic_vlan {
|
||||
int s; /* socket on which to listen for new/removed interfaces. */
|
||||
};
|
||||
|
||||
#define DVLAN_CLEAN_BR 0x1
|
||||
#define DVLAN_CLEAN_VLAN 0x2
|
||||
#define DVLAN_CLEAN_VLAN_PORT 0x4
|
||||
|
||||
struct dynamic_iface {
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int usage;
|
||||
int clean;
|
||||
struct dynamic_iface *next;
|
||||
};
|
||||
|
||||
|
||||
/* Increment ref counter for ifname and add clean flag.
|
||||
* If not in list, add it only if some flags are given.
|
||||
*/
|
||||
static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
|
||||
int clean)
|
||||
{
|
||||
struct dynamic_iface *next, **dynamic_ifaces;
|
||||
struct hapd_interfaces *interfaces;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
dynamic_ifaces = &interfaces->vlan_priv;
|
||||
|
||||
for (next = *dynamic_ifaces; next; next = next->next) {
|
||||
if (os_strcmp(ifname, next->ifname) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next->usage++;
|
||||
next->clean |= clean;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clean)
|
||||
return;
|
||||
|
||||
next = os_zalloc(sizeof(*next));
|
||||
if (!next)
|
||||
return;
|
||||
os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
|
||||
next->usage = 1;
|
||||
next->clean = clean;
|
||||
next->next = *dynamic_ifaces;
|
||||
*dynamic_ifaces = next;
|
||||
}
|
||||
|
||||
|
||||
/* Decrement reference counter for given ifname.
|
||||
* Return clean flag iff reference counter was decreased to zero, else zero
|
||||
*/
|
||||
static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
|
||||
struct hapd_interfaces *interfaces;
|
||||
int clean;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
dynamic_ifaces = &interfaces->vlan_priv;
|
||||
|
||||
for (next = *dynamic_ifaces; next; next = next->next) {
|
||||
if (os_strcmp(ifname, next->ifname) == 0)
|
||||
break;
|
||||
prev = next;
|
||||
}
|
||||
|
||||
if (!next)
|
||||
return 0;
|
||||
|
||||
next->usage--;
|
||||
if (next->usage)
|
||||
return 0;
|
||||
|
||||
if (prev)
|
||||
prev->next = next->next;
|
||||
else
|
||||
*dynamic_ifaces = next->next;
|
||||
clean = next->clean;
|
||||
os_free(next);
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_helper(const char *if_name, int up)
|
||||
{
|
||||
@ -481,11 +566,13 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
|
||||
struct hostapd_vlan *vlan = hapd->conf->vlan;
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int vlan_naming = hapd->conf->ssid.vlan_naming;
|
||||
int clean;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
|
||||
|
||||
while (vlan) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
|
||||
vlan->configured = 1;
|
||||
|
||||
if (hapd->conf->vlan_bridge[0]) {
|
||||
os_snprintf(br_name, sizeof(br_name), "%s%d",
|
||||
@ -500,8 +587,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
|
||||
"brvlan%d", vlan->vlan_id);
|
||||
}
|
||||
|
||||
if (!br_addbr(br_name))
|
||||
vlan->clean |= DVLAN_CLEAN_BR;
|
||||
dyn_iface_get(hapd, br_name,
|
||||
br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
|
||||
|
||||
ifconfig_up(br_name);
|
||||
|
||||
@ -517,13 +604,16 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
|
||||
sizeof(vlan_ifname),
|
||||
"vlan%d", vlan->vlan_id);
|
||||
|
||||
clean = 0;
|
||||
ifconfig_up(tagged_interface);
|
||||
if (!vlan_add(tagged_interface, vlan->vlan_id,
|
||||
vlan_ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_VLAN;
|
||||
clean |= DVLAN_CLEAN_VLAN;
|
||||
|
||||
if (!br_addif(br_name, vlan_ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
|
||||
clean |= DVLAN_CLEAN_VLAN_PORT;
|
||||
|
||||
dyn_iface_get(hapd, vlan_ifname, clean);
|
||||
|
||||
ifconfig_up(vlan_ifname);
|
||||
}
|
||||
@ -547,13 +637,15 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
|
||||
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int vlan_naming = hapd->conf->ssid.vlan_naming;
|
||||
int clean;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
|
||||
|
||||
first = prev = vlan;
|
||||
|
||||
while (vlan) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0 &&
|
||||
vlan->configured) {
|
||||
if (hapd->conf->vlan_bridge[0]) {
|
||||
os_snprintf(br_name, sizeof(br_name), "%s%d",
|
||||
hapd->conf->vlan_bridge,
|
||||
@ -581,20 +673,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
|
||||
os_snprintf(vlan_ifname,
|
||||
sizeof(vlan_ifname),
|
||||
"vlan%d", vlan->vlan_id);
|
||||
if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
|
||||
br_delif(br_name, vlan_ifname);
|
||||
ifconfig_down(vlan_ifname);
|
||||
|
||||
if (vlan->clean & DVLAN_CLEAN_VLAN)
|
||||
clean = dyn_iface_put(hapd, vlan_ifname);
|
||||
|
||||
if (clean & DVLAN_CLEAN_VLAN_PORT)
|
||||
br_delif(br_name, vlan_ifname);
|
||||
|
||||
if (clean & DVLAN_CLEAN_VLAN) {
|
||||
ifconfig_down(vlan_ifname);
|
||||
vlan_rem(vlan_ifname);
|
||||
}
|
||||
}
|
||||
|
||||
if ((vlan->clean & DVLAN_CLEAN_BR) &&
|
||||
clean = dyn_iface_put(hapd, br_name);
|
||||
if ((clean & DVLAN_CLEAN_BR) &&
|
||||
br_getnumports(br_name) == 0) {
|
||||
ifconfig_down(br_name);
|
||||
br_delbr(br_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||
if (vlan == first) {
|
||||
hapd->conf->vlan = vlan->next;
|
||||
} else {
|
||||
@ -651,6 +750,11 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
|
||||
|
||||
if (!ifname[0])
|
||||
return;
|
||||
if (del && if_nametoindex(ifname)) {
|
||||
/* interface still exists, race condition ->
|
||||
* iface has just been recreated */
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
|
||||
@ -778,8 +882,7 @@ static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
struct hostapd_ssid *mssid, const char *dyn_vlan)
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -789,10 +892,11 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
|
||||
* functions for setting up dynamic broadcast keys. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (mssid->wep.key[i] &&
|
||||
if (hapd->conf->ssid.wep.key[i] &&
|
||||
hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
|
||||
i == mssid->wep.idx, NULL, 0,
|
||||
mssid->wep.key[i], mssid->wep.len[i]))
|
||||
i == hapd->conf->ssid.wep.idx, NULL, 0,
|
||||
hapd->conf->ssid.wep.key[i],
|
||||
hapd->conf->ssid.wep.len[i]))
|
||||
{
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
|
||||
"encryption for dynamic VLAN");
|
||||
@ -953,7 +1057,8 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
|
||||
return 1;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
|
||||
__func__, hapd->conf->iface, vlan_id);
|
||||
|
||||
vlan = hapd->conf->vlan;
|
||||
while (vlan) {
|
||||
@ -967,8 +1072,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||
if (vlan == NULL)
|
||||
return 1;
|
||||
|
||||
if (vlan->dynamic_vlan == 0)
|
||||
if (vlan->dynamic_vlan == 0) {
|
||||
hostapd_vlan_if_remove(hapd, vlan->ifname);
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
vlan_dellink(vlan->ifname, hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
int vlan_id);
|
||||
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
struct hostapd_ssid *mssid,
|
||||
const char *dyn_vlan);
|
||||
#else /* CONFIG_NO_VLAN */
|
||||
static inline int vlan_init(struct hostapd_data *hapd)
|
||||
@ -43,7 +42,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||
}
|
||||
|
||||
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
struct hostapd_ssid *mssid,
|
||||
const char *dyn_vlan)
|
||||
{
|
||||
return -1;
|
||||
|
@ -31,7 +31,7 @@
|
||||
*/
|
||||
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
{
|
||||
int ret = -1;
|
||||
int err, ret = -1;
|
||||
struct nl_sock *handle = NULL;
|
||||
struct nl_cache *cache = NULL;
|
||||
struct rtnl_link *rlink = NULL;
|
||||
@ -58,14 +58,18 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
|
||||
err = nl_connect(handle, NETLINK_ROUTE);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
|
||||
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
|
||||
if (err < 0) {
|
||||
cache = NULL;
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
@ -92,23 +96,29 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
if (rtnl_link_set_type(rlink, "vlan") < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
|
||||
err = rtnl_link_set_type(rlink, "vlan");
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
rtnl_link_set_link(rlink, if_idx);
|
||||
rtnl_link_set_name(rlink, vlan_if_name);
|
||||
|
||||
if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
|
||||
err = rtnl_link_vlan_set_id(rlink, vid);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
|
||||
err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
|
||||
"vlan %d on %s (%d)",
|
||||
vlan_if_name, vid, if_name, if_idx);
|
||||
"vlan %d on %s (%d): %s",
|
||||
vlan_if_name, vid, if_name, if_idx,
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
@ -127,7 +137,7 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
|
||||
int vlan_rem(const char *if_name)
|
||||
{
|
||||
int ret = -1;
|
||||
int err, ret = -1;
|
||||
struct nl_sock *handle = NULL;
|
||||
struct nl_cache *cache = NULL;
|
||||
struct rtnl_link *rlink = NULL;
|
||||
@ -140,14 +150,18 @@ int vlan_rem(const char *if_name)
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
|
||||
err = nl_connect(handle, NETLINK_ROUTE);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
|
||||
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
|
||||
if (err < 0) {
|
||||
cache = NULL;
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
@ -158,9 +172,10 @@ int vlan_rem(const char *if_name)
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
if (rtnl_link_delete(handle, rlink) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
|
||||
if_name);
|
||||
err = rtnl_link_delete(handle, rlink);
|
||||
if (err < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
|
||||
if_name, nl_geterror(err));
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
|
@ -274,6 +274,9 @@ void hostapd_wmm_action(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
if (left < 0)
|
||||
return; /* not a valid WMM Action frame */
|
||||
|
||||
/* extract the tspec info element */
|
||||
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
|
@ -45,6 +45,12 @@ 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 void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
|
||||
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
|
||||
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
|
||||
@ -67,6 +73,14 @@ static inline int wpa_auth_mic_failure_report(
|
||||
}
|
||||
|
||||
|
||||
static inline void wpa_auth_psk_failure_report(
|
||||
struct wpa_authenticator *wpa_auth, const u8 *addr)
|
||||
{
|
||||
if (wpa_auth->cb.psk_failure_report)
|
||||
wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
|
||||
}
|
||||
|
||||
|
||||
static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *addr, wpa_eapol_variable var,
|
||||
int value)
|
||||
@ -254,15 +268,22 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
|
||||
static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||
struct wpa_group *group;
|
||||
struct wpa_group *group, *next;
|
||||
|
||||
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
|
||||
for (group = wpa_auth->group; group; group = group->next) {
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
wpa_group_get(wpa_auth, group);
|
||||
|
||||
group->GTKReKey = TRUE;
|
||||
do {
|
||||
group->changed = FALSE;
|
||||
wpa_group_sm_step(wpa_auth, group);
|
||||
} while (group->changed);
|
||||
|
||||
next = group->next;
|
||||
wpa_group_put(wpa_auth, group);
|
||||
group = next;
|
||||
}
|
||||
|
||||
if (wpa_auth->conf.wpa_group_rekey) {
|
||||
@ -565,6 +586,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
|
||||
sm->wpa_auth = wpa_auth;
|
||||
sm->group = wpa_auth->group;
|
||||
wpa_group_get(sm->wpa_auth, sm->group);
|
||||
|
||||
return sm;
|
||||
}
|
||||
@ -643,6 +665,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
os_free(sm->last_rx_eapol_key);
|
||||
os_free(sm->wpa_ie);
|
||||
wpa_group_put(sm->wpa_auth, sm->group);
|
||||
os_free(sm);
|
||||
}
|
||||
|
||||
@ -1517,6 +1540,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
else
|
||||
WPA_PUT_BE16(key->key_data_length,
|
||||
key_data_len);
|
||||
#ifndef CONFIG_NO_RC4
|
||||
} else if (sm->PTK.kek_len == 16) {
|
||||
u8 ek[32];
|
||||
os_memcpy(key->key_iv,
|
||||
@ -1532,6 +1556,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
else
|
||||
WPA_PUT_BE16(key->key_data_length,
|
||||
key_data_len);
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
} else {
|
||||
os_free(hdr);
|
||||
os_free(buf);
|
||||
@ -1646,7 +1671,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
|
||||
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
|
||||
{
|
||||
int remove_ptk = 1;
|
||||
|
||||
@ -1734,6 +1759,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
|
||||
wpa_remove_ptk(sm);
|
||||
}
|
||||
|
||||
if (sm->in_step_loop) {
|
||||
/*
|
||||
* wpa_sm_step() is already running - avoid recursive call to
|
||||
* it by making the existing loop process the new update.
|
||||
*/
|
||||
sm->changed = TRUE;
|
||||
return 0;
|
||||
}
|
||||
return wpa_sm_step(sm);
|
||||
}
|
||||
|
||||
@ -1818,9 +1851,13 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
|
||||
group->reject_4way_hs_for_entropy = FALSE;
|
||||
}
|
||||
|
||||
wpa_group_init_gmk_and_counter(wpa_auth, group);
|
||||
wpa_gtk_update(wpa_auth, group);
|
||||
wpa_group_config_group_keys(wpa_auth, group);
|
||||
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
|
||||
wpa_gtk_update(wpa_auth, group) < 0 ||
|
||||
wpa_group_config_group_keys(wpa_auth, group) < 0) {
|
||||
wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
|
||||
group->first_sta_seen = FALSE;
|
||||
group->reject_4way_hs_for_entropy = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1985,7 +2022,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
{
|
||||
struct wpa_ptk PTK;
|
||||
int ok = 0;
|
||||
int ok = 0, psk_found = 0;
|
||||
const u8 *pmk = NULL;
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||
@ -2001,6 +2038,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
sm->p2p_dev_addr, pmk);
|
||||
if (pmk == NULL)
|
||||
break;
|
||||
psk_found = 1;
|
||||
} else
|
||||
pmk = sm->PMK;
|
||||
|
||||
@ -2020,6 +2058,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
if (!ok) {
|
||||
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"invalid MIC in msg 2/4 of 4-Way Handshake");
|
||||
if (psk_found)
|
||||
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2983,9 +3023,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
|
||||
}
|
||||
|
||||
|
||||
static const char * wpa_bool_txt(int bool)
|
||||
static const char * wpa_bool_txt(int val)
|
||||
{
|
||||
return bool ? "TRUE" : "FALSE";
|
||||
return val ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
||||
|
||||
@ -3270,6 +3310,63 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove and free the group from wpa_authenticator. This is triggered by a
|
||||
* callback to make sure nobody is currently iterating the group list while it
|
||||
* gets modified.
|
||||
*/
|
||||
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group)
|
||||
{
|
||||
struct wpa_group *prev = wpa_auth->group;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
|
||||
group->vlan_id);
|
||||
|
||||
while (prev) {
|
||||
if (prev->next == group) {
|
||||
/* This never frees the special first group as needed */
|
||||
prev->next = group->next;
|
||||
os_free(group);
|
||||
break;
|
||||
}
|
||||
prev = prev->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Increase the reference counter for group */
|
||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group)
|
||||
{
|
||||
/* Skip the special first group */
|
||||
if (wpa_auth->group == group)
|
||||
return;
|
||||
|
||||
group->references++;
|
||||
}
|
||||
|
||||
|
||||
/* Decrease the reference counter and maybe free the group */
|
||||
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group)
|
||||
{
|
||||
/* Skip the special first group */
|
||||
if (wpa_auth->group == group)
|
||||
return;
|
||||
|
||||
group->references--;
|
||||
if (group->references)
|
||||
return;
|
||||
wpa_group_free(wpa_auth, group);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a group that has its references counter set to zero. Caller needs to
|
||||
* call wpa_group_get() on the return value to mark the entry in use.
|
||||
*/
|
||||
static struct wpa_group *
|
||||
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
{
|
||||
@ -3320,7 +3417,10 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
|
||||
wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
|
||||
"machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
|
||||
|
||||
wpa_group_get(sm->wpa_auth, group);
|
||||
wpa_group_put(sm->wpa_auth, sm->group);
|
||||
sm->group = group;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
|
||||
* 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.
|
||||
@ -12,6 +12,9 @@
|
||||
#include "common/defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
#define MAX_OWN_IE_OVERRIDE 256
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
@ -146,8 +149,7 @@ struct wpa_auth_config {
|
||||
int group_mgmt_cipher;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#define SSID_LEN 32
|
||||
u8 ssid[SSID_LEN];
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
|
||||
@ -164,6 +166,8 @@ struct wpa_auth_config {
|
||||
int ap_mlme;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
double corrupt_gtk_rekey_mic_probability;
|
||||
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
|
||||
size_t own_ie_override_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_P2P
|
||||
u8 ip_addr_go[4];
|
||||
@ -189,6 +193,7 @@ struct wpa_auth_callbacks {
|
||||
const char *txt);
|
||||
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
|
||||
int (*mic_failure_report)(void *ctx, const u8 *addr);
|
||||
void (*psk_failure_report)(void *ctx, const u8 *addr);
|
||||
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
|
||||
int value);
|
||||
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
|
||||
@ -251,12 +256,12 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
|
||||
void wpa_receive(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
u8 *data, size_t data_len);
|
||||
typedef enum {
|
||||
enum wpa_event {
|
||||
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
|
||||
WPA_REAUTH_EAPOL, WPA_ASSOC_FT
|
||||
} wpa_event;
|
||||
};
|
||||
void wpa_remove_ptk(struct wpa_state_machine *sm);
|
||||
int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
|
||||
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
|
||||
void wpa_auth_sm_notify(struct wpa_state_machine *sm);
|
||||
void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
|
||||
|
@ -534,10 +534,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
return pos;
|
||||
}
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
|
||||
if (parse.wmm_tspec) {
|
||||
struct wmm_tspec_element *tspec;
|
||||
int res;
|
||||
|
||||
if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
|
||||
@ -555,7 +553,13 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
}
|
||||
tspec = (struct wmm_tspec_element *) pos;
|
||||
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
|
||||
res = wmm_process_tspec(tspec);
|
||||
}
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
|
||||
int res;
|
||||
|
||||
res = wmm_process_tspec((struct wmm_tspec_element *) pos);
|
||||
wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
|
||||
if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
|
||||
rdie->status_code =
|
||||
@ -566,20 +570,17 @@ 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);
|
||||
pos += sizeof(struct wmm_tspec_element);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
|
||||
struct wmm_tspec_element *tspec;
|
||||
int res;
|
||||
|
||||
tspec = (struct wmm_tspec_element *) pos;
|
||||
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
|
||||
res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
|
||||
sizeof(*tspec));
|
||||
sizeof(struct wmm_tspec_element));
|
||||
if (res >= 0) {
|
||||
if (res)
|
||||
rdie->status_code = host_to_le16(res);
|
||||
@ -587,7 +588,7 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
/* TSPEC accepted; include updated TSPEC in
|
||||
* response */
|
||||
rdie->descr_count = 1;
|
||||
pos += sizeof(*tspec);
|
||||
pos += sizeof(struct wmm_tspec_element);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "eap_server/eap.h"
|
||||
@ -53,8 +54,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
wconf->ssid_len = conf->ssid.ssid_len;
|
||||
if (wconf->ssid_len > SSID_LEN)
|
||||
wconf->ssid_len = SSID_LEN;
|
||||
if (wconf->ssid_len > SSID_MAX_LEN)
|
||||
wconf->ssid_len = SSID_MAX_LEN;
|
||||
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
|
||||
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
|
||||
MOBILITY_DOMAIN_ID_LEN);
|
||||
@ -91,6 +92,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wconf->corrupt_gtk_rekey_mic_probability =
|
||||
iconf->corrupt_gtk_rekey_mic_probability;
|
||||
if (conf->own_ie_override &&
|
||||
wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override);
|
||||
os_memcpy(wconf->own_ie_override,
|
||||
wpabuf_head(conf->own_ie_override),
|
||||
wconf->own_ie_override_len);
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_P2P
|
||||
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
|
||||
@ -144,6 +152,14 @@ static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
|
||||
MAC2STR(addr));
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
|
||||
wpa_eapol_variable var, int value)
|
||||
{
|
||||
@ -579,6 +595,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
cb.logger = hostapd_wpa_auth_logger;
|
||||
cb.disconnect = hostapd_wpa_auth_disconnect;
|
||||
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
|
||||
cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
|
||||
cb.set_eapol = hostapd_wpa_auth_set_eapol;
|
||||
cb.get_eapol = hostapd_wpa_auth_get_eapol;
|
||||
cb.get_psk = hostapd_wpa_auth_get_psk;
|
||||
@ -620,7 +637,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (!hostapd_drv_none(hapd)) {
|
||||
if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
|
||||
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
||||
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
|
||||
hapd->conf->bridge :
|
||||
hapd->conf->iface, NULL, ETH_P_RRB,
|
||||
|
@ -169,6 +169,8 @@ struct wpa_group {
|
||||
u8 IGTK[2][WPA_IGTK_MAX_LEN];
|
||||
int GN_igtk, GM_igtk;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
/* Number of references except those in struct wpa_group->next */
|
||||
unsigned int references;
|
||||
};
|
||||
|
||||
|
||||
|
@ -261,7 +261,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
|
||||
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
|
||||
if (pos + 2 + 4 > buf + len)
|
||||
return -1;
|
||||
if (pmkid == NULL) {
|
||||
@ -377,6 +378,23 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
|
||||
u8 *pos, buf[128];
|
||||
int res;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (wpa_auth->conf.own_ie_override_len) {
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
|
||||
wpa_auth->conf.own_ie_override,
|
||||
wpa_auth->conf.own_ie_override_len);
|
||||
os_free(wpa_auth->wpa_ie);
|
||||
wpa_auth->wpa_ie =
|
||||
os_malloc(wpa_auth->conf.own_ie_override_len);
|
||||
if (wpa_auth->wpa_ie == NULL)
|
||||
return -1;
|
||||
os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
|
||||
wpa_auth->conf.own_ie_override_len);
|
||||
wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
pos = buf;
|
||||
|
||||
if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
|
||||
|
@ -324,7 +324,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
|
||||
|
||||
bss->wps_state = 2;
|
||||
if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
|
||||
if (cred->ssid_len <= SSID_MAX_LEN) {
|
||||
os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
|
||||
bss->ssid.ssid_len = cred->ssid_len;
|
||||
bss->ssid.ssid_set = 1;
|
||||
@ -347,8 +347,12 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
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_AES) {
|
||||
if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
|
||||
bss->wpa_pairwise |= WPA_CIPHER_GCMP;
|
||||
else
|
||||
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;
|
||||
@ -448,6 +452,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
os_free(hapd->wps->network_key);
|
||||
hapd->wps->network_key = NULL;
|
||||
hapd->wps->network_key_len = 0;
|
||||
} else if ((cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) &&
|
||||
(cred->key_len < 8 || cred->key_len > 2 * PMK_LEN)) {
|
||||
wpa_printf(MSG_INFO, "WPS: Invalid key length %lu for WPA/WPA2",
|
||||
(unsigned long) cred->key_len);
|
||||
return -1;
|
||||
} else {
|
||||
if (hapd->wps->network_key == NULL ||
|
||||
hapd->wps->network_key_len < cred->key_len) {
|
||||
@ -530,7 +539,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
fprintf(nconf, "wpa_pairwise=");
|
||||
prefix = "";
|
||||
if (cred->encr_type & WPS_ENCR_AES) {
|
||||
fprintf(nconf, "CCMP");
|
||||
if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
|
||||
fprintf(nconf, "GCMP");
|
||||
else
|
||||
fprintf(nconf, "CCMP");
|
||||
|
||||
prefix = " ";
|
||||
}
|
||||
if (cred->encr_type & WPS_ENCR_TKIP) {
|
||||
@ -844,7 +857,9 @@ 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 */
|
||||
WPS_RF_50GHZ :
|
||||
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
|
||||
WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
|
||||
}
|
||||
|
||||
|
||||
@ -856,8 +871,10 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
|
||||
wpabuf_free(hapd->wps_probe_resp_ie);
|
||||
hapd->wps_probe_resp_ie = NULL;
|
||||
|
||||
if (deinit_only)
|
||||
if (deinit_only) {
|
||||
hostapd_reset_ap_wps_ie(hapd);
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_set_ap_wps_ie(hapd);
|
||||
}
|
||||
@ -1039,7 +1056,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
} else {
|
||||
wps->dev.rf_bands =
|
||||
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
|
||||
WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
|
||||
WPS_RF_50GHZ :
|
||||
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
|
||||
WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
|
||||
}
|
||||
|
||||
if (conf->wpa & WPA_PROTO_RSN) {
|
||||
@ -1285,30 +1304,53 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
|
||||
|
||||
struct wps_button_pushed_ctx {
|
||||
const u8 *p2p_dev_addr;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
|
||||
{
|
||||
const u8 *p2p_dev_addr = ctx;
|
||||
if (hapd->wps == NULL)
|
||||
return -1;
|
||||
return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
|
||||
struct wps_button_pushed_ctx *data = ctx;
|
||||
|
||||
if (hapd->wps) {
|
||||
data->count++;
|
||||
return wps_registrar_button_pushed(hapd->wps->registrar,
|
||||
data->p2p_dev_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
|
||||
const u8 *p2p_dev_addr)
|
||||
{
|
||||
return hostapd_wps_for_each(hapd, wps_button_pushed,
|
||||
(void *) p2p_dev_addr);
|
||||
struct wps_button_pushed_ctx ctx;
|
||||
int ret;
|
||||
|
||||
os_memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.p2p_dev_addr = p2p_dev_addr;
|
||||
ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx);
|
||||
if (ret == 0 && !ctx.count)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct wps_cancel_ctx {
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
static int wps_cancel(struct hostapd_data *hapd, void *ctx)
|
||||
{
|
||||
if (hapd->wps == NULL)
|
||||
return -1;
|
||||
struct wps_cancel_ctx *data = ctx;
|
||||
|
||||
wps_registrar_wps_cancel(hapd->wps->registrar);
|
||||
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
|
||||
if (hapd->wps) {
|
||||
data->count++;
|
||||
wps_registrar_wps_cancel(hapd->wps->registrar);
|
||||
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1316,7 +1358,14 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
|
||||
|
||||
int hostapd_wps_cancel(struct hostapd_data *hapd)
|
||||
{
|
||||
return hostapd_wps_for_each(hapd, wps_cancel, NULL);
|
||||
struct wps_cancel_ctx ctx;
|
||||
int ret;
|
||||
|
||||
os_memset(&ctx, 0, sizeof(ctx));
|
||||
ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx);
|
||||
if (ret == 0 && !ctx.count)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1546,6 +1595,10 @@ struct wps_ap_pin_data {
|
||||
static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
|
||||
{
|
||||
struct wps_ap_pin_data *data = ctx;
|
||||
|
||||
if (!hapd->wps)
|
||||
return 0;
|
||||
|
||||
os_free(hapd->conf->ap_pin);
|
||||
hapd->conf->ap_pin = os_strdup(data->pin_txt);
|
||||
#ifdef CONFIG_WPS_UPNP
|
||||
|
@ -51,6 +51,14 @@ int x_snoop_init(struct hostapd_data *hapd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"x_snoop: Failed to enable multicast snooping on the bridge");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IPV6 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* common module tests
|
||||
* Copyright (c) 2014, Jouni Malinen <j@w1.fi>
|
||||
* 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.
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "ieee802_11_common.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "gas.h"
|
||||
#include "wpa_common.h"
|
||||
|
||||
|
||||
@ -46,6 +48,10 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
|
||||
{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
|
||||
{ (u8 *) "\x03\x00\x2a\x00\x36\x00\x37\x00\x38\x00\x2d\x00\x3d\x00\xbf\x00\xc0\x00",
|
||||
18, ParseOK, 9 },
|
||||
{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
|
||||
{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
|
||||
{ NULL, 0, ParseOK, 0 }
|
||||
};
|
||||
|
||||
@ -158,6 +164,34 @@ static int rsn_ie_parse_tests(void)
|
||||
}
|
||||
|
||||
|
||||
static int gas_tests(void)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
wpa_printf(MSG_INFO, "gas tests");
|
||||
gas_anqp_set_len(NULL);
|
||||
|
||||
buf = wpabuf_alloc(1);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
gas_anqp_set_len(buf);
|
||||
wpabuf_free(buf);
|
||||
|
||||
buf = wpabuf_alloc(20);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
|
||||
wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
|
||||
wpabuf_put_u8(buf, 0);
|
||||
wpabuf_put_be32(buf, 0);
|
||||
wpabuf_put_u8(buf, 0);
|
||||
gas_anqp_set_len(buf);
|
||||
wpabuf_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int common_module_tests(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -165,6 +199,7 @@ int common_module_tests(void)
|
||||
wpa_printf(MSG_INFO, "common module tests");
|
||||
|
||||
if (ieee802_11_parse_tests() < 0 ||
|
||||
gas_tests() < 0 ||
|
||||
rsn_ie_parse_tests() < 0)
|
||||
ret = -1;
|
||||
|
||||
|
@ -174,7 +174,7 @@ enum wpa_states {
|
||||
/**
|
||||
* WPA_INTERFACE_DISABLED - Interface disabled
|
||||
*
|
||||
* This stat eis entered if the network interface is disabled, e.g.,
|
||||
* This state is entered if the network interface is disabled, e.g.,
|
||||
* due to rfkill. wpa_supplicant refuses any new operations that would
|
||||
* use the radio until the interface has been enabled.
|
||||
*/
|
||||
@ -295,6 +295,7 @@ enum hostapd_hw_mode {
|
||||
HOSTAPD_MODE_IEEE80211G,
|
||||
HOSTAPD_MODE_IEEE80211A,
|
||||
HOSTAPD_MODE_IEEE80211AD,
|
||||
HOSTAPD_MODE_IEEE80211ANY,
|
||||
NUM_HOSTAPD_MODES
|
||||
};
|
||||
|
||||
@ -310,6 +311,7 @@ enum wpa_ctrl_req_type {
|
||||
WPA_CTRL_REQ_EAP_OTP,
|
||||
WPA_CTRL_REQ_EAP_PASSPHRASE,
|
||||
WPA_CTRL_REQ_SIM,
|
||||
WPA_CTRL_REQ_PSK_PASSPHRASE,
|
||||
NUM_WPA_CTRL_REQS
|
||||
};
|
||||
|
||||
@ -326,4 +328,10 @@ enum mesh_plink_state {
|
||||
PLINK_BLOCKED,
|
||||
};
|
||||
|
||||
enum set_band {
|
||||
WPA_SETBAND_AUTO,
|
||||
WPA_SETBAND_5G,
|
||||
WPA_SETBAND_2G
|
||||
};
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
@ -88,8 +88,8 @@ 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 };
|
||||
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
|
||||
149, 157, 184, 192 };
|
||||
size_t k;
|
||||
|
||||
if (pri_chan == sec_chan || !sec_chan)
|
||||
@ -152,8 +152,7 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
|
||||
*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)) {
|
||||
if (elems.ht_operation) {
|
||||
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
|
||||
*pri_chan = oper->primary_chan;
|
||||
if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
|
||||
@ -177,10 +176,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
|
||||
size_t i;
|
||||
int match;
|
||||
|
||||
if (!mode || !scan_res || !pri_chan || !sec_chan)
|
||||
return 0;
|
||||
|
||||
if (pri_chan == sec_chan)
|
||||
if (!mode || !scan_res || !pri_chan || !sec_chan ||
|
||||
pri_chan == sec_chan)
|
||||
return 0;
|
||||
|
||||
pri_freq = hw_get_freq(mode, pri_chan);
|
||||
@ -238,7 +235,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
|
||||
}
|
||||
|
||||
|
||||
int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
|
||||
static 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;
|
||||
@ -253,8 +251,7 @@ int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (elems.ht_operation &&
|
||||
elems.ht_operation_len >= sizeof(*oper)) {
|
||||
if (elems.ht_operation) {
|
||||
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
|
||||
if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
|
||||
return 0;
|
||||
@ -275,10 +272,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
int affected_start, affected_end;
|
||||
size_t i;
|
||||
|
||||
if (!mode || !scan_res || !pri_chan || !sec_chan)
|
||||
return 0;
|
||||
|
||||
if (pri_chan == sec_chan)
|
||||
if (!mode || !scan_res || !pri_chan || !sec_chan ||
|
||||
pri_chan == sec_chan)
|
||||
return 0;
|
||||
|
||||
pri_freq = hw_get_freq(mode, pri_chan);
|
||||
@ -335,9 +330,7 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
|
||||
|
||||
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)) {
|
||||
if (elems.ht_capabilities) {
|
||||
struct ieee80211_ht_capabilities *ht_cap =
|
||||
(struct ieee80211_ht_capabilities *)
|
||||
elems.ht_capabilities;
|
||||
@ -363,8 +356,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
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;
|
||||
@ -378,11 +369,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
|
||||
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)
|
||||
if (center_segment1 ||
|
||||
(center_segment0 != 0 &&
|
||||
5000 + center_segment0 * 5 != data->center_freq1 &&
|
||||
2407 + center_segment0 * 5 != data->center_freq1))
|
||||
return -1;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
@ -398,19 +388,38 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
/* fall through */
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
data->bandwidth = 80;
|
||||
if (vht_oper_chwidth == 1 && center_segment1)
|
||||
if ((vht_oper_chwidth == 1 && center_segment1) ||
|
||||
(vht_oper_chwidth == 3 && !center_segment1) ||
|
||||
!sec_channel_offset)
|
||||
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;
|
||||
if (!center_segment0) {
|
||||
if (channel <= 48)
|
||||
center_segment0 = 42;
|
||||
else if (channel <= 64)
|
||||
center_segment0 = 58;
|
||||
else if (channel <= 112)
|
||||
center_segment0 = 106;
|
||||
else if (channel <= 128)
|
||||
center_segment0 = 122;
|
||||
else if (channel <= 144)
|
||||
center_segment0 = 138;
|
||||
else if (channel <= 161)
|
||||
center_segment0 = 155;
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
} else {
|
||||
/*
|
||||
* Note: HT/VHT config and params are coupled. Check if
|
||||
* HT40 channel band is in VHT80 Pri channel band
|
||||
* configuration.
|
||||
*/
|
||||
if (center_segment0 == channel + 6 ||
|
||||
center_segment0 == channel + 2 ||
|
||||
center_segment0 == channel - 2 ||
|
||||
center_segment0 == channel - 6)
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
data->bandwidth = 160;
|
||||
@ -424,13 +433,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
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)
|
||||
/*
|
||||
* Note: HT/VHT config and params are coupled. Check if
|
||||
* HT40 channel band is in VHT160 channel band configuration.
|
||||
*/
|
||||
if (center_segment0 == channel + 14 ||
|
||||
center_segment0 == channel + 10 ||
|
||||
center_segment0 == channel + 6 ||
|
||||
center_segment0 == channel + 2 ||
|
||||
center_segment0 == channel - 2 ||
|
||||
center_segment0 == channel - 6 ||
|
||||
center_segment0 == channel - 10 ||
|
||||
center_segment0 == channel - 14)
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
else
|
||||
return -1;
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ 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);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2013, 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.
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "defs.h"
|
||||
#include "wpa_common.h"
|
||||
#include "qca-vendor.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "ieee802_11_common.h"
|
||||
|
||||
@ -146,6 +148,20 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
}
|
||||
break;
|
||||
|
||||
case OUI_QCA:
|
||||
switch (pos[3]) {
|
||||
case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
|
||||
elems->pref_freq_list = pos;
|
||||
elems->pref_freq_list_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE,
|
||||
"Unknown QCA information element ignored (type=%d len=%lu)",
|
||||
pos[3], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
|
||||
"information element ignored (vendor OUI "
|
||||
@ -196,6 +212,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
if (elen > SSID_MAX_LEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignored too long SSID element (elen=%u)",
|
||||
elen);
|
||||
break;
|
||||
}
|
||||
elems->ssid = pos;
|
||||
elems->ssid_len = elen;
|
||||
break;
|
||||
@ -204,8 +226,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_DS_PARAMS:
|
||||
if (elen < 1)
|
||||
break;
|
||||
elems->ds_params = pos;
|
||||
elems->ds_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CF_PARAMS:
|
||||
case WLAN_EID_TIM:
|
||||
@ -215,8 +238,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->challenge_len = elen;
|
||||
break;
|
||||
case WLAN_EID_ERP_INFO:
|
||||
if (elen < 1)
|
||||
break;
|
||||
elems->erp_info = pos;
|
||||
elems->erp_info_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
elems->ext_supp_rates = pos;
|
||||
@ -239,24 +263,31 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->supp_channels_len = elen;
|
||||
break;
|
||||
case WLAN_EID_MOBILITY_DOMAIN:
|
||||
if (elen < sizeof(struct rsn_mdie))
|
||||
break;
|
||||
elems->mdie = pos;
|
||||
elems->mdie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FAST_BSS_TRANSITION:
|
||||
if (elen < sizeof(struct rsn_ftie))
|
||||
break;
|
||||
elems->ftie = pos;
|
||||
elems->ftie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIMEOUT_INTERVAL:
|
||||
if (elen != 5)
|
||||
break;
|
||||
elems->timeout_int = pos;
|
||||
elems->timeout_int_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_CAP:
|
||||
if (elen < sizeof(struct ieee80211_ht_capabilities))
|
||||
break;
|
||||
elems->ht_capabilities = pos;
|
||||
elems->ht_capabilities_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_OPERATION:
|
||||
if (elen < sizeof(struct ieee80211_ht_operation))
|
||||
break;
|
||||
elems->ht_operation = pos;
|
||||
elems->ht_operation_len = elen;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
elems->mesh_config = pos;
|
||||
@ -271,12 +302,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->peer_mgmt_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VHT_CAP:
|
||||
if (elen < sizeof(struct ieee80211_vht_capabilities))
|
||||
break;
|
||||
elems->vht_capabilities = pos;
|
||||
elems->vht_capabilities_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VHT_OPERATION:
|
||||
if (elen < sizeof(struct ieee80211_vht_operation))
|
||||
break;
|
||||
elems->vht_operation = pos;
|
||||
elems->vht_operation_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
|
||||
if (elen != 1)
|
||||
@ -321,6 +354,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
/* after mic everything is encrypted, so stop. */
|
||||
left = elen;
|
||||
break;
|
||||
case WLAN_EID_MULTI_BAND:
|
||||
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
|
||||
id, elen);
|
||||
break;
|
||||
}
|
||||
|
||||
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
|
||||
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
|
||||
elems->mb_ies.nof_ies++;
|
||||
break;
|
||||
default:
|
||||
unknown++;
|
||||
if (!show_errors)
|
||||
@ -486,14 +531,14 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
|
||||
ac->aifs = v;
|
||||
} else if (os_strcmp(pos, "cwmin") == 0) {
|
||||
v = atoi(val);
|
||||
if (v < 0 || v > 12) {
|
||||
if (v < 0 || v > 15) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
|
||||
return -1;
|
||||
}
|
||||
ac->cwmin = v;
|
||||
} else if (os_strcmp(pos, "cwmax") == 0) {
|
||||
v = atoi(val);
|
||||
if (v < 0 || v > 12) {
|
||||
if (v < 0 || v > 15) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
|
||||
return -1;
|
||||
}
|
||||
@ -523,50 +568,163 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
|
||||
|
||||
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
{
|
||||
enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
|
||||
u8 op_class;
|
||||
|
||||
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;
|
||||
return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
|
||||
}
|
||||
|
||||
|
||||
static const char *us_op_class_cc[] = {
|
||||
/**
|
||||
* ieee80211_freq_to_channel_ext - Convert frequency into channel info
|
||||
* for HT40 and VHT. DFS channels are not covered.
|
||||
* @freq: Frequency (MHz) to convert
|
||||
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
|
||||
* @vht: 0 - non-VHT, 1 - 80 MHz
|
||||
* @op_class: Buffer for returning operating class
|
||||
* @channel: Buffer for returning channel number
|
||||
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
|
||||
*/
|
||||
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel)
|
||||
{
|
||||
/* TODO: more operating classes */
|
||||
|
||||
if (sec_channel > 1 || sec_channel < -1)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (freq >= 2412 && freq <= 2472) {
|
||||
if ((freq - 2407) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (vht)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
/* 2.407 GHz, channels 1..13 */
|
||||
if (sec_channel == 1)
|
||||
*op_class = 83;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 84;
|
||||
else
|
||||
*op_class = 81;
|
||||
|
||||
*channel = (freq - 2407) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211G;
|
||||
}
|
||||
|
||||
if (freq == 2484) {
|
||||
if (sec_channel || vht)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
*op_class = 82; /* channel 14 */
|
||||
*channel = 14;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211B;
|
||||
}
|
||||
|
||||
if (freq >= 4900 && freq < 5000) {
|
||||
if ((freq - 4000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
*channel = (freq - 4000) / 5;
|
||||
*op_class = 0; /* TODO */
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 36..48 */
|
||||
if (freq >= 5180 && freq <= 5240) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (sec_channel == 1)
|
||||
*op_class = 116;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 117;
|
||||
else if (vht)
|
||||
*op_class = 128;
|
||||
else
|
||||
*op_class = 115;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..161 */
|
||||
if (freq >= 5745 && freq <= 5805) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (sec_channel == 1)
|
||||
*op_class = 126;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 127;
|
||||
else if (vht)
|
||||
*op_class = 128;
|
||||
else
|
||||
*op_class = 124;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..169 */
|
||||
if (freq >= 5745 && freq <= 5845) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
*op_class = 125;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
if (freq >= 5000 && freq < 5900) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
*channel = (freq - 5000) / 5;
|
||||
*op_class = 0; /* TODO */
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 56.16 GHz, channel 1..4 */
|
||||
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
|
||||
if (sec_channel || vht)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
*channel = (freq - 56160) / 2160;
|
||||
*op_class = 180;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211AD;
|
||||
}
|
||||
|
||||
return NUM_HOSTAPD_MODES;
|
||||
}
|
||||
|
||||
|
||||
static const char *const us_op_class_cc[] = {
|
||||
"US", "CA", NULL
|
||||
};
|
||||
|
||||
static const char *eu_op_class_cc[] = {
|
||||
static const char *const 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[] = {
|
||||
static const char *const jp_op_class_cc[] = {
|
||||
"JP", NULL
|
||||
};
|
||||
|
||||
static const char *cn_op_class_cc[] = {
|
||||
"CN", "CA", NULL
|
||||
static const char *const cn_op_class_cc[] = {
|
||||
"CN", NULL
|
||||
};
|
||||
|
||||
|
||||
static int country_match(const char *cc[], const char *country)
|
||||
static int country_match(const char *const cc[], const char *const country)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -612,6 +770,10 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
|
||||
if (chan < 149 || chan > 161)
|
||||
return -1;
|
||||
return 5000 + 5 * chan;
|
||||
case 5: /* channels 149,153,157,161,165 */
|
||||
if (chan < 149 || chan > 165)
|
||||
return -1;
|
||||
return 5000 + 5 * chan;
|
||||
case 34: /* 60 GHz band, channels 1..3 */
|
||||
if (chan < 1 || chan > 3)
|
||||
return -1;
|
||||
@ -764,12 +926,15 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
|
||||
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 125: /* channels 149,153,157,161,165,169 */
|
||||
if (chan < 149 || chan > 169)
|
||||
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)
|
||||
@ -921,3 +1086,62 @@ const char * fc2str(u16 fc)
|
||||
return "WLAN_FC_TYPE_UNKNOWN";
|
||||
#undef C2S
|
||||
}
|
||||
|
||||
|
||||
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
size_t ies_len)
|
||||
{
|
||||
os_memset(info, 0, sizeof(*info));
|
||||
|
||||
while (ies_buf && ies_len >= 2 &&
|
||||
info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
|
||||
size_t len = 2 + ies_buf[1];
|
||||
|
||||
if (len > ies_len) {
|
||||
wpa_hexdump(MSG_DEBUG, "Truncated IEs",
|
||||
ies_buf, ies_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
|
||||
wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
|
||||
info->ies[info->nof_ies].ie = ies_buf + 2;
|
||||
info->ies[info->nof_ies].ie_len = ies_buf[1];
|
||||
info->nof_ies++;
|
||||
}
|
||||
|
||||
ies_len -= len;
|
||||
ies_buf += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
|
||||
{
|
||||
struct wpabuf *mb_ies = NULL;
|
||||
|
||||
WPA_ASSERT(info != NULL);
|
||||
|
||||
if (info->nof_ies) {
|
||||
u8 i;
|
||||
size_t mb_ies_size = 0;
|
||||
|
||||
for (i = 0; i < info->nof_ies; i++)
|
||||
mb_ies_size += 2 + info->ies[i].ie_len;
|
||||
|
||||
mb_ies = wpabuf_alloc(mb_ies_size);
|
||||
if (mb_ies) {
|
||||
for (i = 0; i < info->nof_ies; i++) {
|
||||
wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
|
||||
wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
|
||||
wpabuf_put_data(mb_ies,
|
||||
info->ies[i].ie,
|
||||
info->ies[i].ie_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mb_ies;
|
||||
}
|
||||
|
@ -9,6 +9,16 @@
|
||||
#ifndef IEEE802_11_COMMON_H
|
||||
#define IEEE802_11_COMMON_H
|
||||
|
||||
#define MAX_NOF_MB_IES_SUPPORTED 5
|
||||
|
||||
struct mb_ies_info {
|
||||
struct {
|
||||
const u8 *ie;
|
||||
u8 ie_len;
|
||||
} ies[MAX_NOF_MB_IES_SUPPORTED];
|
||||
u8 nof_ies;
|
||||
};
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
const u8 *ssid;
|
||||
@ -48,12 +58,11 @@ struct ieee802_11_elems {
|
||||
const u8 *osen;
|
||||
const u8 *ampe;
|
||||
const u8 *mic;
|
||||
const u8 *pref_freq_list;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
u8 ds_params_len;
|
||||
u8 challenge_len;
|
||||
u8 erp_info_len;
|
||||
u8 ext_supp_rates_len;
|
||||
u8 wpa_ie_len;
|
||||
u8 rsn_ie_len;
|
||||
@ -63,14 +72,9 @@ struct ieee802_11_elems {
|
||||
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;
|
||||
@ -83,6 +87,8 @@ struct ieee802_11_elems {
|
||||
u8 osen_len;
|
||||
u8 ampe_len;
|
||||
u8 mic_len;
|
||||
u8 pref_freq_list_len;
|
||||
struct mb_ies_info mb_ies;
|
||||
};
|
||||
|
||||
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
||||
@ -108,9 +114,15 @@ 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);
|
||||
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel);
|
||||
int ieee80211_is_dfs(int freq);
|
||||
|
||||
int supp_rates_11b_only(struct ieee802_11_elems *elems);
|
||||
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
size_t ies_len);
|
||||
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
|
||||
|
||||
const char * fc2str(u16 fc);
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
@ -10,6 +10,8 @@
|
||||
#ifndef IEEE802_11_DEFS_H
|
||||
#define IEEE802_11_DEFS_H
|
||||
|
||||
#include <utils/common.h>
|
||||
|
||||
/* IEEE 802.11 defines */
|
||||
|
||||
#define WLAN_FC_PVER 0x0003
|
||||
@ -163,7 +165,10 @@
|
||||
#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_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
|
||||
#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
|
||||
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
|
||||
#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
|
||||
|
||||
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
|
||||
@ -269,6 +274,8 @@
|
||||
#define WLAN_EID_AMPE 139
|
||||
#define WLAN_EID_MIC 140
|
||||
#define WLAN_EID_CCKM 156
|
||||
#define WLAN_EID_MULTI_BAND 158
|
||||
#define WLAN_EID_SESSION_TRANSITION 164
|
||||
#define WLAN_EID_VHT_CAP 191
|
||||
#define WLAN_EID_VHT_OPERATION 192
|
||||
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
|
||||
@ -297,6 +304,7 @@
|
||||
#define WLAN_ACTION_TDLS 12
|
||||
#define WLAN_ACTION_SELF_PROTECTED 15
|
||||
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
|
||||
#define WLAN_ACTION_FST 18
|
||||
#define WLAN_ACTION_VENDOR_SPECIFIC 127
|
||||
|
||||
/* Public action codes */
|
||||
@ -470,35 +478,35 @@ struct ieee80211_mgmt {
|
||||
le16 auth_transaction;
|
||||
le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED auth;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED deauth;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED assoc_req;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 status_code;
|
||||
le16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
u8 current_ap[6];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED reassoc_req;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED disassoc;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
@ -506,7 +514,7 @@ struct ieee80211_mgmt {
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED beacon;
|
||||
struct {
|
||||
/* only variable items: SSID, Supported rates */
|
||||
@ -518,7 +526,7 @@ struct ieee80211_mgmt {
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED probe_resp;
|
||||
struct {
|
||||
u8 category;
|
||||
@ -527,7 +535,7 @@ struct ieee80211_mgmt {
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED wmm_action;
|
||||
struct{
|
||||
u8 action_code;
|
||||
@ -541,14 +549,14 @@ struct ieee80211_mgmt {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
u8 variable[0]; /* FT Request */
|
||||
u8 variable[]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_req;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
le16 status_code;
|
||||
u8 variable[0]; /* FT Request */
|
||||
u8 variable[]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
@ -561,23 +569,23 @@ struct ieee80211_mgmt {
|
||||
struct {
|
||||
u8 action;
|
||||
u8 dialogtoken;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED wnm_sleep_req;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 dialogtoken;
|
||||
le16 keydata_len;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED wnm_sleep_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED public_action;
|
||||
struct {
|
||||
u8 action; /* 9 */
|
||||
u8 oui[3];
|
||||
/* Vendor-specific content */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED vs_public_action;
|
||||
struct {
|
||||
u8 action; /* 7 */
|
||||
@ -589,7 +597,7 @@ struct ieee80211_mgmt {
|
||||
* Session Information URL (optional),
|
||||
* BSS Transition Candidate List
|
||||
* Entries */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED bss_tm_req;
|
||||
struct {
|
||||
u8 action; /* 8 */
|
||||
@ -599,7 +607,7 @@ struct ieee80211_mgmt {
|
||||
/* Target BSSID (optional),
|
||||
* BSS Transition Candidate List
|
||||
* Entries (optional) */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED bss_tm_resp;
|
||||
struct {
|
||||
u8 action; /* 6 */
|
||||
@ -607,12 +615,16 @@ struct ieee80211_mgmt {
|
||||
u8 query_reason;
|
||||
/* BSS Transition Candidate List
|
||||
* Entries (optional) */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED bss_tm_query;
|
||||
struct {
|
||||
u8 action; /* 15 */
|
||||
u8 variable[0];
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED slf_prot_action;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED fst_action;
|
||||
} u;
|
||||
} STRUCT_PACKED action;
|
||||
} u;
|
||||
@ -1065,6 +1077,15 @@ enum p2p_attr_id {
|
||||
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
|
||||
#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
|
||||
|
||||
/* P2PS Coordination Protocol Transport Bitmap */
|
||||
#define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
|
||||
#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
|
||||
|
||||
struct p2ps_feature_capab {
|
||||
u8 cpt;
|
||||
u8 reserved;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* Invitation Flags */
|
||||
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
|
||||
|
||||
@ -1354,4 +1375,62 @@ struct rrm_link_measurement_report {
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
|
||||
/* IEEE Std 802.11ad-2012 - Multi-band element */
|
||||
struct multi_band_ie {
|
||||
u8 eid; /* WLAN_EID_MULTI_BAND */
|
||||
u8 len;
|
||||
u8 mb_ctrl;
|
||||
u8 band_id;
|
||||
u8 op_class;
|
||||
u8 chan;
|
||||
u8 bssid[ETH_ALEN];
|
||||
le16 beacon_int;
|
||||
u8 tsf_offs[8];
|
||||
u8 mb_connection_capability;
|
||||
u8 fst_session_tmout;
|
||||
/* Optional:
|
||||
* STA MAC Address
|
||||
* Pairwise Cipher Suite Count
|
||||
* Pairwise Cipher Suite List
|
||||
*/
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
enum mb_ctrl_sta_role {
|
||||
MB_STA_ROLE_AP = 0,
|
||||
MB_STA_ROLE_TDLS_STA = 1,
|
||||
MB_STA_ROLE_IBSS_STA = 2,
|
||||
MB_STA_ROLE_PCP = 3,
|
||||
MB_STA_ROLE_NON_PCP_NON_AP = 4
|
||||
};
|
||||
|
||||
#define MB_CTRL_ROLE_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
#define MB_CTRL_ROLE(ctrl) ((u8) ((ctrl) & MB_CTRL_ROLE_MASK))
|
||||
#define MB_CTRL_STA_MAC_PRESENT ((u8) (BIT(3)))
|
||||
#define MB_CTRL_PAIRWISE_CIPHER_SUITE_PRESENT ((u8) (BIT(4)))
|
||||
|
||||
enum mb_band_id {
|
||||
MB_BAND_ID_WIFI_2_4GHZ = 2, /* 2.4 GHz */
|
||||
MB_BAND_ID_WIFI_5GHZ = 4, /* 4.9 and 5 GHz */
|
||||
MB_BAND_ID_WIFI_60GHZ = 5, /* 60 GHz */
|
||||
};
|
||||
|
||||
#define MB_CONNECTION_CAPABILITY_AP ((u8) (BIT(0)))
|
||||
#define MB_CONNECTION_CAPABILITY_PCP ((u8) (BIT(1)))
|
||||
#define MB_CONNECTION_CAPABILITY_DLS ((u8) (BIT(2)))
|
||||
#define MB_CONNECTION_CAPABILITY_TDLS ((u8) (BIT(3)))
|
||||
#define MB_CONNECTION_CAPABILITY_IBSS ((u8) (BIT(4)))
|
||||
|
||||
/* IEEE Std 802.11ad-2014 - FST Action field */
|
||||
enum fst_action {
|
||||
FST_ACTION_SETUP_REQUEST = 0,
|
||||
FST_ACTION_SETUP_RESPONSE = 1,
|
||||
FST_ACTION_TEAR_DOWN = 2,
|
||||
FST_ACTION_ACK_REQUEST = 3,
|
||||
FST_ACTION_ACK_RESPONSE = 4,
|
||||
FST_ACTION_ON_CHANNEL_TUNNEL = 5,
|
||||
};
|
||||
|
||||
#endif /* IEEE802_11_DEFS_H */
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef PRIVSEP_COMMANDS_H
|
||||
#define PRIVSEP_COMMANDS_H
|
||||
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
enum privsep_cmd {
|
||||
PRIVSEP_CMD_REGISTER,
|
||||
PRIVSEP_CMD_UNREGISTER,
|
||||
@ -24,12 +26,31 @@ enum privsep_cmd {
|
||||
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
|
||||
PRIVSEP_CMD_L2_SEND,
|
||||
PRIVSEP_CMD_SET_COUNTRY,
|
||||
PRIVSEP_CMD_AUTHENTICATE,
|
||||
};
|
||||
|
||||
struct privsep_cmd_authenticate
|
||||
{
|
||||
int freq;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
int auth_alg;
|
||||
size_t ie_len;
|
||||
u8 wep_key[4][16];
|
||||
size_t wep_key_len[4];
|
||||
int wep_tx_keyidx;
|
||||
int local_state_change;
|
||||
int p2p;
|
||||
size_t sae_data_len;
|
||||
/* followed by ie_len bytes of ie */
|
||||
/* followed by sae_data_len bytes of sae_data */
|
||||
};
|
||||
|
||||
struct privsep_cmd_associate
|
||||
{
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 ssid[32];
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
int hwmode;
|
||||
int freq;
|
||||
@ -66,6 +87,18 @@ enum privsep_event {
|
||||
PRIVSEP_EVENT_STKSTART,
|
||||
PRIVSEP_EVENT_FT_RESPONSE,
|
||||
PRIVSEP_EVENT_RX_EAPOL,
|
||||
PRIVSEP_EVENT_SCAN_STARTED,
|
||||
PRIVSEP_EVENT_AUTH,
|
||||
};
|
||||
|
||||
struct privsep_event_auth {
|
||||
u8 peer[ETH_ALEN];
|
||||
u8 bssid[ETH_ALEN];
|
||||
u16 auth_type;
|
||||
u16 auth_transaction;
|
||||
u16 status_code;
|
||||
size_t ies_len;
|
||||
/* followed by ies_len bytes of ies */
|
||||
};
|
||||
|
||||
#endif /* PRIVSEP_COMMANDS_H */
|
||||
|
@ -132,7 +132,7 @@ enum qca_nl80211_vendor_subcmds {
|
||||
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 */
|
||||
/* 53 - reserved - was used by QCA, but not in use anymore */
|
||||
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
|
||||
QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
|
||||
@ -142,6 +142,20 @@ enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
|
||||
/* 61-90 - reserved for QCA */
|
||||
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95,
|
||||
QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
|
||||
QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
|
||||
QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG = 102,
|
||||
QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
|
||||
QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
|
||||
QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
|
||||
};
|
||||
|
||||
|
||||
@ -162,6 +176,15 @@ enum qca_wlan_vendor_attr {
|
||||
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
|
||||
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
|
||||
QCA_WLAN_VENDOR_ATTR_TEST = 8,
|
||||
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
|
||||
/* Unsigned 32-bit value. */
|
||||
QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9,
|
||||
/* Unsigned 32-bit value */
|
||||
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
|
||||
/* Unsigned 32-bit value */
|
||||
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
|
||||
/* Unsigned 32-bit value from enum qca_set_band. */
|
||||
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
|
||||
@ -195,6 +218,12 @@ enum qca_wlan_vendor_attr_acs_offload {
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
|
||||
@ -206,6 +235,7 @@ enum qca_wlan_vendor_acs_hw_mode {
|
||||
QCA_ACS_MODE_IEEE80211G,
|
||||
QCA_ACS_MODE_IEEE80211A,
|
||||
QCA_ACS_MODE_IEEE80211AD,
|
||||
QCA_ACS_MODE_IEEE80211ANY,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -215,10 +245,13 @@ enum qca_wlan_vendor_acs_hw_mode {
|
||||
* 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.
|
||||
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
|
||||
* band selection based on channel selection results.
|
||||
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
|
||||
*/
|
||||
enum qca_wlan_vendor_features {
|
||||
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
|
||||
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
|
||||
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
|
||||
};
|
||||
|
||||
@ -243,4 +276,82 @@ enum qca_wlan_vendor_attr_data_offload_ind {
|
||||
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
enum qca_vendor_attr_get_preferred_freq_list {
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID,
|
||||
/* A 32-unsigned value; the interface type/mode for which the preferred
|
||||
* frequency list is requested (see enum qca_iface_type for possible
|
||||
* values); used in GET_PREFERRED_FREQ_LIST command from user-space to
|
||||
* kernel and in the kernel response back to user-space.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
|
||||
/* An array of 32-unsigned values; values are frequency (MHz); sent
|
||||
* from kernel space to user space.
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
enum qca_vendor_attr_probable_oper_channel {
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID,
|
||||
/* 32-bit unsigned value; indicates the connection/iface type likely to
|
||||
* come on this channel (see enum qca_iface_type).
|
||||
*/
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
|
||||
/* 32-bit unsigned value; the frequency (MHz) of the probable channel */
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
|
||||
/* keep last */
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST,
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX =
|
||||
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
enum qca_iface_type {
|
||||
QCA_IFACE_TYPE_STA,
|
||||
QCA_IFACE_TYPE_AP,
|
||||
QCA_IFACE_TYPE_P2P_CLIENT,
|
||||
QCA_IFACE_TYPE_P2P_GO,
|
||||
QCA_IFACE_TYPE_IBSS,
|
||||
QCA_IFACE_TYPE_TDLS,
|
||||
};
|
||||
|
||||
enum qca_set_band {
|
||||
QCA_SETBAND_AUTO,
|
||||
QCA_SETBAND_5G,
|
||||
QCA_SETBAND_2G,
|
||||
};
|
||||
|
||||
/* IEEE 802.11 Vendor Specific elements */
|
||||
|
||||
/**
|
||||
* enum qca_vendor_element_id - QCA Vendor Specific element types
|
||||
*
|
||||
* These values are used to identify QCA Vendor Specific elements. The
|
||||
* payload of the element starts with the three octet OUI (OUI_QCA) and
|
||||
* is followed by a single octet type which is defined by this enum.
|
||||
*
|
||||
* @QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: P2P preferred channel list.
|
||||
* This element can be used to specify preference order for supported
|
||||
* channels. The channels in this list are in preference order (the first
|
||||
* one has the highest preference) and are described as a pair of
|
||||
* (global) Operating Class and Channel Number (each one octet) fields.
|
||||
*
|
||||
* This extends the standard P2P functionality by providing option to have
|
||||
* more than one preferred operating channel. When this element is present,
|
||||
* it replaces the preference indicated in the Operating Channel attribute.
|
||||
* For supporting other implementations, the Operating Channel attribute is
|
||||
* expected to be used with the highest preference channel. Similarly, all
|
||||
* the channels included in this Preferred channel list element are
|
||||
* expected to be included in the Channel List attribute.
|
||||
*
|
||||
* This vendor element may be included in GO Negotiation Request, P2P
|
||||
* Invitation Request, and Provision Discovery Request frames.
|
||||
*/
|
||||
enum qca_vendor_element_id {
|
||||
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
|
||||
};
|
||||
|
||||
#endif /* QCA_VENDOR_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Simultaneous authentication of equals
|
||||
* Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -124,9 +124,7 @@ static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
if (iter++ > 100)
|
||||
return NULL;
|
||||
if (random_get_bytes(val, order_len) < 0)
|
||||
if (iter++ > 100 || 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);
|
||||
@ -171,17 +169,107 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
|
||||
}
|
||||
|
||||
|
||||
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
struct crypto_ec_point *pwe)
|
||||
static struct crypto_bignum *
|
||||
get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
|
||||
int *r_odd)
|
||||
{
|
||||
u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *x;
|
||||
int y_bit;
|
||||
for (;;) {
|
||||
struct crypto_bignum *r;
|
||||
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
|
||||
|
||||
if (random_get_bytes(tmp, prime_len) < 0)
|
||||
break;
|
||||
if (prime_bits % 8)
|
||||
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
|
||||
if (os_memcmp(tmp, prime, prime_len) >= 0)
|
||||
continue;
|
||||
r = crypto_bignum_init_set(tmp, prime_len);
|
||||
if (!r)
|
||||
break;
|
||||
if (crypto_bignum_is_zero(r)) {
|
||||
crypto_bignum_deinit(r, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
*r_odd = tmp[prime_len - 1] & 0x01;
|
||||
return r;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int is_quadratic_residue_blind(struct sae_data *sae,
|
||||
const u8 *prime, size_t bits,
|
||||
const struct crypto_bignum *qr,
|
||||
const struct crypto_bignum *qnr,
|
||||
const struct crypto_bignum *y_sqr)
|
||||
{
|
||||
struct crypto_bignum *r, *num;
|
||||
int r_odd, check, res = -1;
|
||||
|
||||
/*
|
||||
* Use the blinding technique to mask y_sqr while determining
|
||||
* whether it is a quadratic residue modulo p to avoid leaking
|
||||
* timing information while determining the Legendre symbol.
|
||||
*
|
||||
* v = y_sqr
|
||||
* r = a random number between 1 and p-1, inclusive
|
||||
* num = (v * r * r) modulo p
|
||||
*/
|
||||
r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
|
||||
if (!r)
|
||||
return -1;
|
||||
|
||||
num = crypto_bignum_init();
|
||||
if (!num ||
|
||||
crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
|
||||
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
|
||||
if (r_odd) {
|
||||
/*
|
||||
* num = (num * qr) module p
|
||||
* LGR(num, p) = 1 ==> quadratic residue
|
||||
*/
|
||||
if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
check = 1;
|
||||
} else {
|
||||
/*
|
||||
* num = (num * qnr) module p
|
||||
* LGR(num, p) = -1 ==> quadratic residue
|
||||
*/
|
||||
if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
|
||||
goto fail;
|
||||
check = -1;
|
||||
}
|
||||
|
||||
res = crypto_bignum_legendre(num, sae->tmp->prime);
|
||||
if (res == -2) {
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
res = res == check;
|
||||
fail:
|
||||
crypto_bignum_deinit(num, 1);
|
||||
crypto_bignum_deinit(r, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
const u8 *prime,
|
||||
const struct crypto_bignum *qr,
|
||||
const struct crypto_bignum *qnr,
|
||||
struct crypto_bignum **ret_x_cand)
|
||||
{
|
||||
u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *y_sqr, *x_cand;
|
||||
int res;
|
||||
size_t bits;
|
||||
|
||||
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
|
||||
sae->tmp->prime_len) < 0)
|
||||
return -1;
|
||||
*ret_x_cand = NULL;
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
|
||||
|
||||
@ -197,20 +285,23 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
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)
|
||||
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
|
||||
if (!x_cand)
|
||||
return -1;
|
||||
y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
|
||||
if (!y_sqr) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
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");
|
||||
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
|
||||
crypto_bignum_deinit(y_sqr, 1);
|
||||
if (res <= 0) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
*ret_x_cand = x_cand;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -288,24 +379,77 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
}
|
||||
|
||||
|
||||
static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
|
||||
const struct crypto_bignum *prime_bn,
|
||||
size_t prime_bits, struct crypto_bignum **qr,
|
||||
struct crypto_bignum **qnr)
|
||||
{
|
||||
*qr = NULL;
|
||||
*qnr = NULL;
|
||||
|
||||
while (!(*qr) || !(*qnr)) {
|
||||
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
|
||||
struct crypto_bignum *q;
|
||||
int res;
|
||||
|
||||
if (random_get_bytes(tmp, prime_len) < 0)
|
||||
break;
|
||||
if (prime_bits % 8)
|
||||
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
|
||||
if (os_memcmp(tmp, prime, prime_len) >= 0)
|
||||
continue;
|
||||
q = crypto_bignum_init_set(tmp, prime_len);
|
||||
if (!q)
|
||||
break;
|
||||
res = crypto_bignum_legendre(q, prime_bn);
|
||||
|
||||
if (res == 1 && !(*qr))
|
||||
*qr = q;
|
||||
else if (res == -1 && !(*qnr))
|
||||
*qnr = q;
|
||||
else
|
||||
crypto_bignum_deinit(q, 0);
|
||||
}
|
||||
|
||||
return (*qr && *qnr) ? 0 : -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 counter, k = 40;
|
||||
u8 addrs[2 * ETH_ALEN];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
int found = 0;
|
||||
struct crypto_ec_point *pwe_tmp;
|
||||
u8 dummy_password[32];
|
||||
size_t dummy_password_len;
|
||||
int pwd_seed_odd = 0;
|
||||
u8 prime[SAE_MAX_ECC_PRIME_LEN];
|
||||
size_t prime_len;
|
||||
struct crypto_bignum *x = NULL, *qr, *qnr;
|
||||
size_t bits;
|
||||
int res;
|
||||
|
||||
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)
|
||||
dummy_password_len = password_len;
|
||||
if (dummy_password_len > sizeof(dummy_password))
|
||||
dummy_password_len = sizeof(dummy_password);
|
||||
if (random_get_bytes(dummy_password, dummy_password_len) < 0)
|
||||
return -1;
|
||||
|
||||
prime_len = sae->tmp->prime_len;
|
||||
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
|
||||
prime_len) < 0)
|
||||
return -1;
|
||||
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
|
||||
|
||||
/*
|
||||
* Create a random quadratic residue (qr) and quadratic non-residue
|
||||
* (qnr) modulo p for blinding purposes during the loop.
|
||||
*/
|
||||
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
|
||||
&qr, &qnr) < 0)
|
||||
return -1;
|
||||
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
|
||||
@ -313,8 +457,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
|
||||
/*
|
||||
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
|
||||
* base = password
|
||||
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
|
||||
* password || counter)
|
||||
* base || counter)
|
||||
*/
|
||||
sae_pwd_seed_key(addr1, addr2, addrs);
|
||||
|
||||
@ -328,9 +473,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
* attacks that attempt to determine the number of iterations required
|
||||
* in the loop.
|
||||
*/
|
||||
for (counter = 1; counter < k || !found; counter++) {
|
||||
for (counter = 1; counter <= k || !x; counter++) {
|
||||
u8 pwd_seed[SHA256_MAC_LEN];
|
||||
int res;
|
||||
struct crypto_bignum *x_cand;
|
||||
|
||||
if (counter > 200) {
|
||||
/* This should not happen in practice */
|
||||
@ -342,25 +487,58 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
|
||||
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);
|
||||
prime, qr, qnr, &x_cand);
|
||||
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;
|
||||
goto fail;
|
||||
if (res > 0 && !x) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: Selected pwd-seed with counter %u",
|
||||
counter);
|
||||
x = x_cand;
|
||||
pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
|
||||
os_memset(pwd_seed, 0, sizeof(pwd_seed));
|
||||
|
||||
/*
|
||||
* Use a dummy password for the following rounds, if
|
||||
* any.
|
||||
*/
|
||||
addr[0] = dummy_password;
|
||||
len[0] = dummy_password_len;
|
||||
} else if (res > 0) {
|
||||
crypto_bignum_deinit(x_cand, 1);
|
||||
}
|
||||
}
|
||||
|
||||
crypto_ec_point_deinit(pwe_tmp, 1);
|
||||
if (!x) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
|
||||
res = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return found ? 0 : -1;
|
||||
if (!sae->tmp->pwe_ecc)
|
||||
sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
|
||||
if (!sae->tmp->pwe_ecc)
|
||||
res = -1;
|
||||
else
|
||||
res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
|
||||
sae->tmp->pwe_ecc, x,
|
||||
pwd_seed_odd);
|
||||
crypto_bignum_deinit(x, 1);
|
||||
if (res < 0) {
|
||||
/*
|
||||
* This should not happen since we already checked that there
|
||||
* is a result.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
|
||||
}
|
||||
|
||||
fail:
|
||||
crypto_bignum_deinit(qr, 0);
|
||||
crypto_bignum_deinit(qnr, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -472,27 +650,41 @@ static int sae_derive_commit(struct sae_data *sae)
|
||||
{
|
||||
struct crypto_bignum *mask;
|
||||
int ret = -1;
|
||||
unsigned int counter = 0;
|
||||
|
||||
mask = sae_get_rand_and_mask(sae);
|
||||
if (mask == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
|
||||
return -1;
|
||||
}
|
||||
do {
|
||||
counter++;
|
||||
if (counter > 100) {
|
||||
/*
|
||||
* This cannot really happen in practice if the random
|
||||
* number generator is working. Anyway, to avoid even a
|
||||
* theoretical infinite loop, break out after 100
|
||||
* attemps.
|
||||
*/
|
||||
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);
|
||||
mask = sae_get_rand_and_mask(sae);
|
||||
if (mask == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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)
|
||||
/* 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);
|
||||
} while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
|
||||
crypto_bignum_is_one(sae->tmp->own_commit_scalar));
|
||||
|
||||
if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
|
||||
(sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
@ -506,15 +698,12 @@ 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)
|
||||
if (sae->tmp == NULL ||
|
||||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
|
||||
password_len) < 0) ||
|
||||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
|
||||
password_len) < 0) ||
|
||||
sae_derive_commit(sae) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@ -780,8 +969,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
/* 0 < scalar < r */
|
||||
/* 1 < scalar < r */
|
||||
if (crypto_bignum_is_zero(peer_scalar) ||
|
||||
crypto_bignum_is_one(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);
|
||||
@ -847,7 +1037,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
|
||||
static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
|
||||
const u8 *end)
|
||||
{
|
||||
struct crypto_bignum *res;
|
||||
struct crypto_bignum *res, *one;
|
||||
const u8 one_bin[1] = { 0x01 };
|
||||
|
||||
if (pos + sae->tmp->prime_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
|
||||
@ -862,18 +1053,23 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
|
||||
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) ||
|
||||
/* 1 < element < p - 1 */
|
||||
res = crypto_bignum_init();
|
||||
one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
|
||||
if (!res || !one ||
|
||||
crypto_bignum_sub(sae->tmp->prime, one, res) ||
|
||||
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) {
|
||||
crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
|
||||
crypto_bignum_deinit(res, 0);
|
||||
crypto_bignum_deinit(one, 0);
|
||||
wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
crypto_bignum_deinit(one, 0);
|
||||
|
||||
/* scalar-op(r, ELEMENT) = 1 modulo p */
|
||||
res = crypto_bignum_init();
|
||||
if (res == NULL ||
|
||||
crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
|
||||
if (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)");
|
||||
@ -918,7 +1114,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
|
||||
return res;
|
||||
|
||||
/* commit-element */
|
||||
return sae_parse_commit_element(sae, pos, end);
|
||||
res = sae_parse_commit_element(sae, pos, end);
|
||||
if (res != WLAN_STATUS_SUCCESS)
|
||||
return res;
|
||||
|
||||
/*
|
||||
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
|
||||
* the values we sent which would be evidence of a reflection attack.
|
||||
*/
|
||||
if (!sae->tmp->own_commit_scalar ||
|
||||
crypto_bignum_cmp(sae->tmp->own_commit_scalar,
|
||||
sae->peer_commit_scalar) != 0 ||
|
||||
(sae->tmp->dh &&
|
||||
(!sae->tmp->own_commit_element_ffc ||
|
||||
crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
|
||||
sae->tmp->peer_commit_element_ffc) != 0)) ||
|
||||
(sae->tmp->ec &&
|
||||
(!sae->tmp->own_commit_element_ecc ||
|
||||
crypto_ec_point_cmp(sae->tmp->ec,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
sae->tmp->peer_commit_element_ecc) != 0)))
|
||||
return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
|
||||
|
||||
/*
|
||||
* This is a reflection attack - return special value to trigger caller
|
||||
* to silently discard the frame instead of replying with a specific
|
||||
* status code.
|
||||
*/
|
||||
return SAE_SILENTLY_DISCARD;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
|
||||
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
|
||||
|
||||
/* Special value returned by sae_parse_commit() */
|
||||
#define SAE_SILENTLY_DISCARD 65535
|
||||
|
||||
struct sae_temporary_data {
|
||||
u8 kck[SAE_KCK_LEN];
|
||||
struct crypto_bignum *own_commit_scalar;
|
||||
|
@ -5,6 +5,6 @@
|
||||
#define VERSION_STR_POSTFIX ""
|
||||
#endif /* VERSION_STR_POSTFIX */
|
||||
|
||||
#define VERSION_STR "2.4" VERSION_STR_POSTFIX
|
||||
#define VERSION_STR "2.5" VERSION_STR_POSTFIX
|
||||
|
||||
#endif /* VERSION_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user