diff --git a/chroot-buildpackages.sh b/chroot-buildpackages.sh index aa1ad533f9..01db652f8d 100644 --- a/chroot-buildpackages.sh +++ b/chroot-buildpackages.sh @@ -13,6 +13,7 @@ # update_chroot # chroot_build_packages # fetch_from_repo +# chroot_installpackages # create_chroot # : directory to put files @@ -73,6 +74,12 @@ chroot_build_packages() display_alert "Starting package building process" "$RELEASE" "info" local target_dir=$DEST/buildpkg/${RELEASE}-${ARCH} + # to avoid conflicts between published and self-built packages + # higher pin-priority may be enough + # may use hostname or other unique identifier + # local builddate=$(date +"%Y%m%d") + + mkdir -p $DEST/debs/extra/$RELEASE [[ ! -f $target_dir/root/.debootstrap-complete ]] && create_chroot "$target_dir" @@ -81,13 +88,16 @@ chroot_build_packages() update_chroot "$target_dir" for plugin in $SRC/lib/extras-buildpkgs/*.conf; do + unset package_name package_repo package_ref package_builddeps package_install_chroot package_install_target \ + package_prebuild_eval package_upstream_version needs_building source $plugin # check if needs building local needs_building=no if [[ -n $package_install_target ]]; then for f in $package_install_target; do - if [[ -z $(find $DEST/debs/extra/ -name "${f}_*$REVISION*_$ARCH.deb") ]]; then + if [[ -z $(find $DEST/debs/extra/$RELEASE/ -name "${f}_*$REVISION*_$ARCH.deb" \ + -o -name "${f}_*$REVISION*_all.deb") ]]; then needs_building=yes break fi @@ -128,6 +138,7 @@ chroot_build_packages() # set upstream version [[ -n "$package_upstream_version" ]] && debchange --preserve --newversion "$package_upstream_version" "Import from upstream" # set local version + # debchange -l~armbian${REVISION}-${builddate}+ "New Armbian release" debchange -l~armbian${REVISION}+ "New Armbian release" # build display_alert "Building package" @@ -158,16 +169,14 @@ chroot_build_packages() # run build script in chroot systemd-nspawn -a -q -D $target_dir --tmpfs=/root/build --tmpfs=/tmp --bind-ro $SRC/lib/extras-buildpkgs/:/root/overlay \ --bind-ro $SRC/sources/extra/:/root/sources /bin/bash -c "/root/build.sh" - # move built packages to $DEST/debs/extras + # move built packages to $DEST/debs/extras/$RELEASE if [[ -n $package_install_target ]]; then for f in $package_install_target; do - mv $target_dir/root/${f}_*.deb $DEST/debs/extra/ + mv $target_dir/root/${f}_*.deb $DEST/debs/extra/$RELEASE/ done fi # cleanup rm $target_dir/root/*.deb 2>/dev/null - unset package_name package_repo package_ref package_builddeps package_install_chroot package_install_target \ - package_prebuild_eval package_upstream_version needs_building done } ############################################################################# @@ -196,6 +205,7 @@ fetch_from_repo() # doesn't work with git:// remote URLs # local ref_name=$(git ls-remote --symref $url HEAD | grep -o 'refs/heads/\S*' | sed 's%refs/heads/%%') + # TODO: Remove hardcoded "extra" part if [[ $ref_subdir == yes ]]; then mkdir -p $SOURCES/extra/$dir/$ref_name cd $SOURCES/extra/$dir/$ref_name @@ -239,3 +249,63 @@ fetch_from_repo() display_alert "... up to date" fi } ############################################################################# + +# chroot_installpackages +# +chroot_installpackages() +{ + local conf="/tmp/aptly-temp/aptly.conf" + mkdir -p /tmp/aptly-temp/ + cat <<-'EOF' > $conf + { + "rootDir": "/tmp/aptly-temp/", + "downloadConcurrency": 4, + "downloadSpeedLimit": 0, + "architectures": [], + "dependencyFollowSuggests": false, + "dependencyFollowRecommends": false, + "dependencyFollowAllVariants": false, + "dependencyFollowSource": false, + "gpgDisableSign": false, + "gpgDisableVerify": false, + "downloadSourcePackages": false, + "ppaDistributorID": "ubuntu", + "ppaCodename": "", + "S3PublishEndpoints": {}, + "SwiftPublishEndpoints": {} + } + EOF + aptly -config=$conf repo create temp + # NOTE: this works recursively + aptly -config=$conf -force-replace=true repo add temp $DEST/debs/extra/$RELEASE/ + # -gpg-key="128290AF" + aptly -secret-keyring="$SRC/lib/extras-buildpkgs/buildpkg.gpg" -batch -config=$conf \ + -component=temp -distribution=$RELEASE publish repo temp + aptly -config=$conf -listen=":8189" serve & + local aptly_pid=$! + cp $SRC/lib/extras-buildpkgs/buildpkg.key $CACHEDIR/sdcard/tmp/buildpkg.key + chroot $CACHEDIR/sdcard /bin/bash -c "cat /tmp/buildpkg.key | apt-key add -" + rm $CACHEDIR/sdcard/tmp/buildpkg.key + cat <<-EOF > $CACHEDIR/sdcard/etc/apt/preferences.d/90-armbian-temp.pref + Package: * + Pin: origin "localhost" + Pin-Priority: 995 + EOF + cat <<-EOF > $CACHEDIR/sdcard/etc/apt/sources.list.d/armbian-temp.list + deb http://localhost:8189/ $RELEASE temp + EOF + local install_list="" + for plugin in $SRC/lib/extras-buildpkgs/*.conf; do + source $plugin + # TODO: check install condition + install_list="$install_list $package_install_target" + unset package_install_target + done + chroot $CACHEDIR/sdcard /bin/bash -c "apt-get update; apt-get install -y $install_list" + rm $CACHEDIR/sdcard/etc/apt/sources.list.d/armbian-temp.list + chroot $CACHEDIR/sdcard /bin/bash -c "apt-key del 128290AF" + rm $CACHEDIR/sdcard/etc/apt/preferences.d/90-armbian-temp.pref + kill $aptly_pid + rm -rf /tmp/aptly-temp/ + +} ############################################################################# diff --git a/extras-buildpkgs/00-libdri2.conf b/extras-buildpkgs/00-libdri2.conf index 005c7cb125..5d95b6373c 100644 --- a/extras-buildpkgs/00-libdri2.conf +++ b/extras-buildpkgs/00-libdri2.conf @@ -2,6 +2,7 @@ local package_name="libDRI2" local package_repo="https://github.com/robclark/libdri2.git" local package_ref="branch:master" +local package_upstream_version="1.0.1" local package_builddeps="xutils-dev x11proto-xext-dev x11proto-dri2-dev quilt pkg-config libxfixes-dev libxext-dev libdrm-dev dh-autoreconf" local package_install_chroot="libdri2-1 libdri2-dev" local package_install_target="libdri2-1" diff --git a/extras-buildpkgs/90-hostapd-realtek.conf b/extras-buildpkgs/90-hostapd-realtek.conf new file mode 100644 index 0000000000..5520b3b263 --- /dev/null +++ b/extras-buildpkgs/90-hostapd-realtek.conf @@ -0,0 +1,7 @@ +# hostapd-realtek +local package_name="hostapd-realtek" +local package_repo="http://w1.fi/hostap.git" +local package_ref="branch:hostap_2_5" +local package_upstream_version="2.5" +local package_builddeps="pkg-config libssl-dev libreadline-dev libpcsclite-dev libnl-route-3-dev libnl-genl-3-dev libnl-3-dev libncurses5-dev libdbus-1-dev docbook-utils docbook-to-man" +local package_install_target="hostapd-realtek" diff --git a/extras-buildpkgs/README.md b/extras-buildpkgs/README.md index c99b532599..e29aaeaf5b 100644 --- a/extras-buildpkgs/README.md +++ b/extras-buildpkgs/README.md @@ -2,11 +2,11 @@ ### Installing packages to images: -* Add a function for installing packages +* Add a function for installing packages - **done** * ~~Add a variable for dependencies or function for extracting dependencies from deb files~~ -* Use aptly to create local repository: this will allow solving dependencies on installation automatically +* Use aptly to create local repository: this will allow solving dependencies on installation automatically - **done** * Add a variable for list of packages to install during debootstrap - **done** @@ -27,7 +27,7 @@ * Add sunxi-mali package if BLOBs license allows redistribution, otherwise create an installer like oracle-jdk -* Add hostapd-realtek package - copy of hostapd with realtek-specific patches +* Add hostapd-realtek package - copy of hostapd with realtek-specific patches - **done** * Delete unused files (i.e. \*.lintian-overrides) - **done*** diff --git a/extras-buildpkgs/buildpkg.gpg b/extras-buildpkgs/buildpkg.gpg new file mode 100644 index 0000000000..9d5aefcf6b Binary files /dev/null and b/extras-buildpkgs/buildpkg.gpg differ diff --git a/extras-buildpkgs/buildpkg.key b/extras-buildpkgs/buildpkg.key new file mode 100644 index 0000000000..b641b68c4a --- /dev/null +++ b/extras-buildpkgs/buildpkg.key @@ -0,0 +1,38 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFeCxc0BCADazdDUs6OG4nRR+u2eeGvtfutGRqGPuk7F6iqFzzSnw0/iXwIW +tgWAp1bqlXjQXBQ+1qpvnYQAUt9q7tQ06b53gxI+ROG+Wv8nRxdT5xhBVwydtoRf +vV8wBTE504eRF9EuOjp2KhIVpGUEkBVXrSEHDk51Tiz9TKKtS3/HSoicNAnFCHix ++XuXcdJ+INcsnnDV9XOfaqCdUdpeaDAjQT1q7YHqrAYShjByryrmw2tE3TSff05y +h8fdWATGlJQBRvNBrlKDSBGlNbMYpnOaKC30F3f3RHq4cPb37RgPlEAZ8EL1U43h +cYJHGDI0anIP+G93nUOWNSAMyP9+2nBnG88rABEBAAG0ZkFybWJpYW4gYnVpbGRl +ciAoVGVtcG9yYXJ5IGtleSBmb3IgaW5zdGFsbGluZyBwYWNrYWdlcyBkdXJpbmcg +QXJtYmlhbiBpbWFnZSBjcmVhdGlvbikgPHJvb3RAbG9jYWxob3N0PokBOAQTAQIA +IgUCV4LFzQIbLwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQqDKDcBKCkK+s +lQgAmUA3erGtEdzorjbcfF8nvqzaq/oiwYCgz3maMzcOv4QIfd+uUbjPYlkNoAql +j4Gamqo/oVDcW91kLk4pScNstQ3CueE+1HuFSLVD9v3x0dU2wo4XmV5d0J7LQo/K +CVI3ZjpI1eKiqIFBQDbRn92EiTLjy0pv1KtN3PXHOKNHwuz3cD/CQvh0lhgN+mb4 +yGtVrlZlvtjy9EqQBYd6FCBGVygHae/2GvrEJq2CeGAQogNSXZS2A+kjRMdJZod5 +reFXXXtUqxrnDCWtqqaH3Vz+w7UoiRSlmCpZXWBRhXrQ3UzBktOV6LeR3EyiBSdW +HVzu3OHeoUjRg1JE+zcj0P4zaLkBDQRXgsXNAQgAuAbsxXys1Ne5jrZF+JyhMnq+ +i0njf75i5Z3rQi2/WjyWNvC8hb866urYFbJ/mcLTcKtqOAMGM7YSmcGnVr+m1jsi +mSvc16mufD/8zyhPeV2s45ajIapc5mdUYgosJuHDEe8j2XAb0XFtC8KW07srk0i8 +g2JAlyn7dLK2mlmgeFOBW17P6Stl+/HIdf6n9Jy1xSk9+NLJfgCP+ATzirHaSs+N +lEatIMYQnjqdby8smTaWvFyQnVcp3NV2NvjKcKWPxLNIq/AEJxEUaI0F3NywLqAA +ziaLIzVX9Rr2LBgHX20S0UA8Vr/1jP30meTqolAbeC/+5bxam8Mvj32allV5dQAR +AQABiQI+BBgBAgAJBQJXgsXNAhsuASkJEKgyg3ASgpCvwF0gBBkBAgAGBQJXgsXN +AAoJEJyHpA2eKEFr2nwH/3vD3RmUq1aIdzW0kgOZBWmSr7uCYNfgRM7NA+MVrXr2 +x7+2STvyZ/Ms7ekbuiBzbXthiZoFUFS6ElANFrmH9Mml1c3ogxB0Fhr7SatOJCPZ +SDq5HqAnbmiDTnDEo+NgYBP3aFfQTKmTogpBr8UP+ZS71BJYtOsh73a//cGtIPRG +JBbjwBwpa2QFnh4AjXBanptsACED768Djvx5CGk9YvVkuet33M0zqE35GwhiPEwz +xuszIbokZpro7tW9fYLgATg6VfLRI35S/qegTernFcYs5yz7V94brUYVn9rHwILz +Dqh5jeEZF0NCcxB1wSmEeDbMSk6cTzMSw94/vgojXtIK9AgAzSkH5EaNcOQpCm1t +nvz6ZlXMWuadgrKdsi797s87taFvb1K5PNjIpv/PWyzCIAIevxPfduz6bwM9h7EW +njozWkmclnW/R0WMm/Ge7ywkT3Jr/9FKHwv5EtcJFK24kwLEq947ujn0DAOSmFAt +TQZoTEAbRApWVfifiFNFpgVTuMh4r69nocxw8lq+vaX3bx3lvHYbog5D/NyijgYb +3cKnCayCJB70hWHvbWswmhw1AOw4W9ALJV6/shg6bCKrFRv9VEXprq2XW5rJsgkC +BZMm7FCG8WbijGjlGNSjE91gUpPPLLjTTquD8wk4wBkOlrmxVQlGlK9CuF0f4ASH +c0x2xw== +=I43U +-----END PGP PUBLIC KEY BLOCK----- diff --git a/extras-buildpkgs/hostapd-realtek/debian/NEWS b/extras-buildpkgs/hostapd-realtek/debian/NEWS new file mode 100644 index 0000000000..6291eb688a --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/NEWS @@ -0,0 +1,20 @@ +wpasupplicant (0.6.2-1) unstable; urgency=low + + The -w (wait for network interface to exist) command line option no longer + exists. If you have scripts that require this option, it is time to change + them, or use one of the two supported modes of operation explained at + /usr/share/doc/wpasupplicant/README.modes.gz. + + ifupdown supports hot-plugged network devices via the "allow-hotplug" class + of operation. An example /etc/network/interfaces configuration stanza would + look like: + + allow-hotplug wlan0 + iface wlan0 inet dhcp + wpa-ssid myssid + wpa-psk mysecretpassphrase + + network-manager is also able to handle hot-plugged network devices. + + -- Kel Modderman Mon, 14 Jan 2008 18:02:17 +1000 + diff --git a/extras-buildpkgs/hostapd-realtek/debian/README.source b/extras-buildpkgs/hostapd-realtek/debian/README.source new file mode 100644 index 0000000000..bb7a4a9d74 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/README.source @@ -0,0 +1,128 @@ +"wpa" sources for Debian +------------------------ + +This "wpa" source package merges wpa_supplicant and hostapd sources, which are +maintained in one source repository[1] upstream and share considerable/ +duplicate amounts of source. Starting with the 1.x branch, both wpa_supplicant +and hostapd are built from this common source package for Debian, while not +released together as tarball by upstream, the source can be obtained from the +upstream git repositories. + +The preferred way to generate the orig.tar.gz is by calling + + $ debian/rules get-orig-source + +which will clone the upstream git repository under $TMPDIR, using mktemp(1), +and create a new tarball based on the git tag corresponding to the top most +entry in debian/changelog. This newly generated tarball will be stored as +../wpa_${VERSION}.orig.tar.gz or ../tarballs/wpa_${VERSION}.orig.tar.gz, if +a directory called ../tarballs/ exists. Eventually existing tarballs +corresponding to the current version will not be overwritten. + +Required dependencies to generate a new orig.tar.gz: +- a SUSv3 compatible shell, like dash or bash +- dpkg-parsechangelog, available from dpkg-dev +- git +- xz, available from xz-utils or busybox +- mktemp and rm, available from coreutils or busybox +- sed, available from sed or busybox +- tar, available from tar or busybox + +It is recommended to base tarballs for development snapshots of "wpa" on +according git tags from the upstream git repository, the available git tags +can be queried by: + + $ git clone git://w1.fi/srv/git/hostap-1.git # 1.x branch + +or + + $ git clone git://w1.fi/srv/git/hostap.git # >= 2.x branches + +changing into the corresponding directory (hostap-1 or hostapd) and calling +git tag. + + $ cd hostapd-1 + $ git tag + hostap_0_6_3 + […] + hostap_1_0 + […] + hostap_1_0_rc3 + […] + +The Debian versions for these tags would be 0.6.3-1, 1.0 or 1.0~rc3 in +debian/changelog. Intermediate states between tags or HEAD are usually best +dealt with by creating a patch series based on the newest matching tag. + +Exporting commits between "hostap_1_0" and the current git HEAD: + + $ git format-patch hostap_1_0..HEAD + +Exporting commits between "hostap_1_0_rc3" and "hostap_1_0": + + $ git format-patch hostap_1_0_rc3..hostap_1_0 + +In both cases numbered patches will be dropped in the base directory of the +git clone. These numbered patches can be imported to the Debian package using +standard procedures for "3.0 (quilt)" source packages. + +Tarballs can also be created manually from the upstream git repository: + + $ git clone git://w1.fi/srv/git/hostap-1.git + $ cd hostap-1 + $ git archive \ + --format=tar \ + --prefix="wpa-1.0/" \ + hostap_1_0 \ + README COPYING patches src wpa_supplicant hostapd | \ + xz -c6 > wpa_1.0.orig.tar.gz + +Arbitrary git tags or commit IDs can be used for this purpose. + + +Upstream git snapshots can be exported by using a specially crafted version +syntax used in the top most (pending) changelog entry. The required syntax for +correctly parsing this is: + + +git.+- + upstream_version := [0-9\.]* --> 2.0 + date := [0-9]* --> 20131120 (YYYYMMDD) + revision := [0-9]* --> 1 + git_hash := [0-9a-f]* --> 594516b + debian_revision := [0-9*] --> 1 + +e.g.: + + 2.0+git20131120.1+594516b-1 + +Technically any incrementing number can be used for , but it's strongly +recommended to use YYYYMMDD (date --utc +%Y%m%d) and follow it by an +strictly incrementing arbitrary revision number (typically '.1'). The supplied +git hash can be abbreviated, but must be unique (see git describe, without +leading 'g'). + +The debian/rules get-orig-source target will automatically switch between +hostapd-1.git and hostapd.git (for >= 2.0) as needed, but it will only fetch +the explicitly specified version from a properly formatted, top most, +debian/changelog entry; it will not fetch the last upstream release or git +HEAD automatically. + + +The Debian packaging for wpa_supplicant/ hostapd is maintained in a subversion +repository at: + + Vcs-Svn: svn://anonscm.debian.org/svn/pkg-wpa/wpa/trunk/ + Vcs-Browser: http://anonscm.debian.org/viewvc/pkg-wpa/wpa/trunk/ + +The development mailing list and its mailing list archive is located at: + + http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-wpa-devel + +Work for the wpa package can be coordinated on this mailing list through: + + Debian wpasupplicant Maintainers + + -- Stefan Lippers-Hollmann Sat, 28 Dec 2013 22:37:03 +0100 + +[1] http://hostap.epitest.fi/gitweb/gitweb.cgi?p=hostap-1.git [1.x branch] + http://hostap.epitest.fi/gitweb/gitweb.cgi?p=hostap.git [development] diff --git a/extras-buildpkgs/hostapd-realtek/debian/changelog b/extras-buildpkgs/hostapd-realtek/debian/changelog new file mode 100644 index 0000000000..782e762933 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/changelog @@ -0,0 +1,39 @@ +wpa (2.4-0ubuntu6) xenial; urgency=medium + + * debian/patches/wpasupplicant_band_selection_aa517ae2.patch: add the last + missing 5 GHz band selection related cherry-pick from Debian that was not + included in wpa 2.4 (LP: #1517040) + + -- Timo Jyrinki Tue, 19 Jan 2016 12:36:00 +0200 + +wpa (2.4-0ubuntu5) xenial; urgency=medium + + * SECURITY UPDATE: unauthorized WNM Sleep Mode GTK control + - debian/patches/CVE-2015-5310.patch: Ignore Key Data in WNM Sleep Mode + Response frame if no PMF in use in wpa_supplicant/wnm_sta.c. + - CVE-2015-5310 + * SECURITY UPDATE: EAP-pwd missing last fragment length validation + - debian/patches/CVE-2015-5315-1.patch: Fix last fragment length + validation in src/eap_peer/eap_pwd.c. + - debian/patches/CVE-2015-5315-2.patch: Fix last fragment length + validation in src/eap_server/eap_server_pwd.c. + - CVE-2015-5315 + * SECURITY UPDATE: EAP-pwd peer error path failure on unexpected Confirm + message + - debian/patches/CVE-2015-5316.patch: fix error path in + src/eap_peer/eap_pwd.c. + - CVE-2015-5316 + * SECURITY UPDATE: denial of service in NDEF record parser + - debian/patches/CVE-2015-8041.patch: validate payload lengths in + src/wps/ndef.c. + - CVE-2015-8041 + + -- Marc Deslauriers Tue, 10 Nov 2015 13:38:25 -0500 + +wpa (2.4-0ubuntu4) xenial; urgency=medium + + * Add debian/system-sleep/wpasupplicant: Call wpa_cli suspend/resume + before/after suspend, like the pm-utils hook. In some cases this brings + back missing Wifi connection after resuming. (LP: #1422143) + + -- Martin Pitt Mon, 26 Oct 2015 14:24:30 +0100 diff --git a/extras-buildpkgs/hostapd-realtek/debian/changelog.hostapd b/extras-buildpkgs/hostapd-realtek/debian/changelog.hostapd new file mode 100644 index 0000000000..a9b987f6f9 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/changelog.hostapd @@ -0,0 +1,54 @@ +hostapd (1:0.7.3-5) UNRELEASED; urgency=low + + * NOT RELEASED YET + * bump standards version to 3.9.3, no changes necessary. + * update dep-5 version to final 1.0: + - add format qualifier + - s/Upstream-Maintainer/Upstream-Contact/ + - s/Upstream-Source/Source/ + - use "or" instead of "BSD | GPL-2" for dual-licensed sources + - order licenses alphabetically. + - fix lists of copyright holders for the final syntax + - fix license continuation. + + -- Stefan Lippers-Hollmann Mon, 27 Feb 2012 22:07:19 +0100 + +hostapd (1:0.7.3-4) unstable; urgency=low + + * add myself to uploaders. + * add "hostap: Allow linking with libnl-3" from Ben Greear + to allow building against libnl3 3.2. + * switch build dependency from libnl-dev (libnl1) to libnl-3-dev && + libnl-genl-3-dev accordingly. + * add libpcap-dev and libbsd-dev to kFreeBSD specific build-depends. + * disable IAPP on kFreeBSD, to avoid FTBS. + * restrict hostapd to linux-any and kfreebsd-any, hurd lacks kernel support. + * raise versioned build-dependency to (>= 3.2.3-2~), we need + libnl-genl-3-200-udeb and expect it in /lib/. + * add "For MS-CHAP, convert the password from UTF-8 to UCS-2" from + Evan Broder , accepted upstream into hostap-1.git + * fix long description, driver_madwifi is no longer enabled, while driver_bsd + got enabled. + + -- Stefan Lippers-Hollmann Tue, 20 Dec 2011 02:51:49 +0100 + +hostapd (1:0.7.3-3) unstable; urgency=low + + [ Kel Modderman ] + * Use /run/sendsigs.omit.d/ for sendsigs omission pid file and depend on + initscripts (>= 2.88dsf-13.3). (Closes: #633026) + * Migrate existing sendsigs omission pid files from /lib/init/rw to /run. + * Add a loop to ifupdown.sh to wait for creation of hostapd pid file before + attempting creation of sensigs omission pid file, in some cases hostapd + daemon can return before creation of the pid file has been written to disk. + * Adjust standards version to 3.9.2, no further changes required to + satisfy that. + * Only test that DAEMON_CONF is set in init.d script, do not test if what is + set is readable (which assumes only one configuration file is being used). + (Closes: #615821) + + [ Stefan Lippers-Hollmann ] + * use new anonscm URIs for alioth. + + -- Kel Modderman Sun, 11 Dec 2011 20:32:06 +1000 + diff --git a/extras-buildpkgs/hostapd-realtek/debian/compat b/extras-buildpkgs/hostapd-realtek/debian/compat new file mode 100644 index 0000000000..ec635144f6 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/compat @@ -0,0 +1 @@ +9 diff --git a/extras-buildpkgs/hostapd/debian/config/config_realtek b/extras-buildpkgs/hostapd-realtek/debian/config/config_realtek similarity index 100% rename from extras-buildpkgs/hostapd/debian/config/config_realtek rename to extras-buildpkgs/hostapd-realtek/debian/config/config_realtek diff --git a/extras-buildpkgs/hostapd-realtek/debian/control b/extras-buildpkgs/hostapd-realtek/debian/control new file mode 100644 index 0000000000..f711602115 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/control @@ -0,0 +1,54 @@ +Source: wpa +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian wpasupplicant Maintainers +Uploaders: Stefan Lippers-Hollmann , + Jan Dittberner +Section: net +Priority: optional +Build-Depends: debhelper (>> 9.20120115), + libdbus-1-dev, + libssl-dev, + libncurses5-dev, + libpcsclite-dev, + libnl-3-dev [linux-any], + libnl-genl-3-dev [linux-any], + libnl-route-3-dev [linux-any], + libpcap-dev [kfreebsd-any], + libbsd-dev [kfreebsd-any], + libreadline-dev, + pkg-config, + docbook-to-man, + docbook-utils, +Standards-Version: 3.9.6 +Vcs-Browser: http://anonscm.debian.org/viewvc/pkg-wpa/wpa/trunk/ +Vcs-Svn: svn://anonscm.debian.org/pkg-wpa/wpa/trunk/ +Homepage: http://w1.fi/wpa_supplicant/ + +Package: hostapd-realtek +Architecture: linux-any kfreebsd-any +Multi-Arch: foreign +Depends: ${shlibs:Depends}, + ${misc:Depends}, + lsb-base +Breaks: initscripts (<< 2.88dsf-13.3) +Provides: hostapd-realtek +Conflicts: hostapd +Description: IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator + Originally, hostapd was an optional user space component for Host AP + driver. It adds more features to the basic IEEE 802.11 management + included in the kernel driver: using external RADIUS authentication + server for MAC address based access control, IEEE 802.1X Authenticator + and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN) + Authenticator and dynamic TKIP/CCMP keying. + . + The current version includes support for other drivers, an integrated + EAP authenticator (i.e., allow full authentication without requiring + an external RADIUS authentication server), and RADIUS authentication + server for EAP authentication. + . + hostapd works with the following drivers: + . + * mac80211 based drivers with support for master mode [linux] + * Host AP driver for Prism2/2.5/3 [linux] + * Driver interface for FreeBSD net80211 layer [kfreebsd] + * Any wired Ethernet driver for wired IEEE 802.1X authentication. diff --git a/extras-buildpkgs/hostapd-realtek/debian/copyright b/extras-buildpkgs/hostapd-realtek/debian/copyright new file mode 100644 index 0000000000..0810beecb1 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/copyright @@ -0,0 +1,422 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: hostapd +Upstream-Contact: Jouni Malinen +Source: git://w1.fi/srv/git/hostap.git + +Files: * +Copyright: 2002-2014, Jouni Malinen +License: BSD-3-clause + +Files: hostapd/logwatch/* +Copyright: 2005, Henrik Brix Andersen +License: BSD-3-clause or GPL-2 + +Files: hostapd/Android.mk +Copyright: 2008, The Android Open Source Project +License: BSD-3-clause + +Files: hostapd/hostapd.8 + hostapd/hostapd_cli.1 +Copyright: 2005, Faidon Liambotis +License: BSD-3-clause + +Files: hs20/* +Copyright: 2012-2014, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: patches/* +Copyright: 2005, Alexey Kobozev + 2005-2012, Jouni Malinen +License: BSD-3-clause + +Files: src/ap/acs.* +Copyright: 2011, Atheros Communications + 2013, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/ap/ap_list.* + src/ap/ap_mlme.* + src/ap/beacon.* + src/ap/hw_features.* + src/ap/vlan_init.* + src/ap/wmm.* +Copyright: 2002-2009, Jouni Malinen + 2002-2004, Instant802 Networks, Inc. + 2005-2006, Devicescape Software, Inc. +License: BSD-3-clause + +Files: src/ap/dfs.* +Copyright: 2002-2013, Jouni Malinen + 2013, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/ap/gas_serv.* + src/ap/wnm_ap.* + src/common/ieee802_1x_defs.h + src/common/qca-vendor* +Copyright: 2011-2014, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/ap/hs20.* + wpa_supplicant/hs20_supplicant.* +Copyright: 2009, Atheros Communications, Inc. + 2011-2013, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/ap/ieee802_11_ht.c +Copyright: 2002-2009, Jouni Malinen + 2007-2008, Intel Corporation +License: BSD-3-clause + +Files: src/ap/p2p_hostapd.* +Copyright: 2009-2010, Atheros Communications +License: BSD-3-clause + +Files: src/ap/vlan_util.* +Copyright: 2012, Michael Braun +License: BSD-3-clause + +Files: src/common/gas.* +Copyright: 2009, Atheros Communications + 2011-2012, Qualcomm Atheros +License: BSD-3-clause + +Files: src/common/ieee802_11_defs.h +Copyright: 2002-2009, Jouni Malinen + 2007-2008, Intel Corporation +License: BSD-3-clause + +Files: src/common/wpa_helpers.* +Copyright: 2010-2011, Atheros Communications, Inc. + 2011-2012, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/crypto/aes-internal* +Copyright: 2000, Vincent Rijmen + 2000, Antoon Bosselaers + 2000, Paulo Barreto + 2003-2012, Jouni Malinen +License: BSD-3-clause + +Files: src/crypto/des-internal.c +Copyright: 2005, Tom St Denis + 2006-2009, Jouni Malinen +License: BSD-3-clause + +Files: src/crypto/md4-internal.c +Copyright: 1993, Colin Plumb + 2004, Todd C. Miller + 2006, Jouni Malinen +License: BSD-3-clause + +Files: src/crypto/md5-internal.c +Copyright: 1993, Colin Plumb + 2003-2005, Jouni Malinen +License: BSD-3-clause + +Files: src/crypto/sha1-internal.c +Copyright: 1998, Steve Reid + 1998, James H. Brown + 2001, Saul Kravitz + 2001-2005, Jouni Malinen +License: BSD-3-clause + +Files: src/drivers/driver_atheros.c +Copyright: 2004, Sam Leffler + 2004, Video54 Technologies + 2005-2007, Jouni Malinen + 2009, Atheros Communications +License: BSD-3-clause + +Files: src/drivers/driver_bsd.c +Copyright: 2004, Sam Leffler + 2004, 2Wire, Inc +License: BSD-3-clause + +Files: src/drivers/driver_macsec_qca.c +Copyright: 2004, Gunter Burchardt + 2005-2009, Jouni Malinen + 2013-2014, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/drivers/driver_madwifi.c +Copyright: 2004, Sam Leffler + 2004, Video54 Technologies + 2004-2007, Jouni Malinen +License: BSD-3-clause + +Files: src/drivers/driver_nl80211.c +Copyright: 2002-2014, Jouni Malinen + 2003-2004, Instant802 Networks, Inc. + 2005-2006, Devicescape Software, Inc. + 2007, Johannes Berg + 2009-2010, Atheros Communications +License: BSD-3-clause + +Files: src/drivers/driver_none.c +Copyright: 2008, Atheros Communications +License: BSD-3-clause + +Files: src/drivers/driver_openbsd.c +Copyright: 2013, Mark Kettenis +License: BSD-3-clause + +Files: src/drivers/driver_roboswitch.c +Copyright: 2008-2009, Jouke Witteveen +License: BSD-3-clause + +Files: src/drivers/driver_wired.c +Copyright: 2005-2009, Jouni Malinen + 2004, Gunter Burchardt +License: BSD-3-clause + +Files: src/drivers/nl80211_copy.h +Copyright: 2006-2010, Johannes Berg + 2008, Michael Wu + 2008, Luis Carlos Cobo + 2008, Michael Buesch + 2008-2009, Luis R. Rodriguez + 2008, Jouni Malinen + 2008, Colin McCabe +License: ISC + +Files: src/eap_common/eap_pwd_common.* + src/eap_peer/eap_pwd.c + src/eap_server/eap_server_pwd.c +Copyright: 2010, Dan Harkins +License: BSD-3-clause + +Files: src/eap_peer/eap_proxy* +Copyright: 2011-2013 Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/l2_packet/l2_packet_freebsd.c +Copyright: 2003-2005, Jouni Malinen + 2005, Sam Leffler +License: BSD-3-clause + +Files: src/p2p/* +Copyright: 2009-2010, Atheros Communications +License: BSD-3-clause + +Files: src/pae/* +Copyright: 2013-2014, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/rsn_supp/tdls.c +Copyright: 2010-2011, Atheros Communications +License: BSD-3-clause + +Files: src/tls/libtommath.c +Copyright: 2005-2007, Tom St Denis +License: public-domain + +Files: src/utils/browser* + src/utils/http* + src/utils/xml* +Copyright: 2012-2014, Qualcomm Atheros, Inc. +License: BSD-3-clause + +Files: src/utils/radiotap.c +Copyright: 2007, Andy Green + 2009, Johannes Berg +License: BSD-3-clause + +Files: src/utils/radiotap.h +Copyright: 2003-2004, David Young +License: BSD-3-clause + +Files: src/wps/http.h + src/wps/upnp_xml.* + src/wps/wps_upnp.* + src/wps/wps_upnp_event.c + src/wps/wps_upnp_i.h + src/wps/wps_upnp_ssdp.c + src/wps/wps_upnp_web.c +Copyright: 2000-2003, Intel Corporation + 2006-2007, Sony Corporation + 2008-2009, Atheros Communications + 2009, Jouni Malinen +License: BSD-3-clause + +Files: src/wps/httpread.* +Copyright: 2008, Ted Merrill, Atheros Communications +License: BSD-3-clause + +Files: src/wps/ndef.c +Copyright: 2009-2012, Masashi Honma +License: BSD-3-clause + +Files: src/wps/wps_validate.c +Copyright: 2010, Atheros Communications, Inc. +License: BSD-3-clause + +Files: wpa_supplicant/dbus/dbus_common.* + wpa_supplicant/dbus/dbus_common_i.h + wpa_supplicant/dbus/dbus_new.* + wpa_supplicant/dbus/dbus_new_handlers.* + wpa_supplicant/dbus/dbus_new_handlers_wps.c + wpa_supplicant/dbus/dbus_new_helpers.* + wpa_supplicant/dbus/dbus_new_introspect.c +Copyright: 2006, Dan Williams and Red Hat, Inc. + 2009-2010, Witold Sowa + 2009-2010, Jouni Malinen +License: BSD-3-clause + +Files: wpa_supplicant/dbus/dbus_dict_helpers.* + wpa_supplicant/dbus/dbus_old* +Copyright: 2006, Dan Williams and Red Hat, Inc. +License: BSD-3-clause + +Files: wpa_supplicant/dbus/dbus_new_handlers_p2p.* + wpa_supplicant/examples/p2p/* + wpa_supplicant/examples/dbus-listen-preq.py +Copyright: 2011-2012, Intel Corporation +License: BSD-3-clause + +Files: wpa_supplicant/utils/log2pcap.py +Copyright: Johannes Berg , Intel Corporation +License: BSD-3-clause + +Files: wpa_supplicant/wpa_gui-qt4/icons/ap.svg +Copyright: 2008, mystica +License: public-domain + +Files: wpa_supplicant/wpa_gui-qt4/icons/group.svg +Copyright: 2009, Andrew Fitzsimon / Anonymous +License: public-domain + +Files: wpa_supplicant/wpa_gui-qt4/icons/invitation.svg +Copyright: 2009, Jean Victor Balin +License: public-domain + +Files: wpa_supplicant/wpa_gui-qt4/icons/laptop.svg +Copyright: 2008, metalmarious +License: public-domain + +Files: wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg +Copyright: 2008, Bernard Gray +License: BSD-3-clause or GPL-2 + +Files: wpa_supplicant/wpa_gui-qt4/peers.* + wpa_supplicant/wpa_gui-qt4/stringquery.* +Copyright: 2009-2010, Atheros Communications +License: BSD-3-clause + +Files: wpa_supplicant/wpa_gui-qt4/signalbar.* +Copyright: 2011, Kel Modderman +License: BSD-3-clause + +Files: wpa_supplicant/Android.mk + wpa_supplicant/wpa_supplicant_conf.* +Copyright: 2008-2010, The Android Open Source Project +License: BSD-3-clause + +Files: wpa_supplicant/ap.* +Copyright: 2003-2009, Jouni Malinen + 2009, Atheros Communications +License: BSD-3-clause + +Files: wpa_supplicant/autoscan* +Copyright: 2012, Intel Corporation +License: BSD-3-clause + +Files: wpa_supplicant/gas_query.* + wpa_supplicant/offchannel.* + wpa_supplicant/p2p_supplicant.* + wpa_supplicant/wifi_display.* +Copyright: 2009-2011, Atheros Communications + 2011-2014, Qualcomm Atheros + 2011-2014, Jouni Malinen +License: BSD-3-clause + +Files: wpa_supplicant/interworking.* + wpa_supplicant/wnm_sta.* + wpa_supplicant/wpas_kay.* +Copyright: 2011-2014, Qualcomm Atheros + 2011-2014, Jouni Malinen +License: BSD-3-clause + +Files: debian/* +Copyright: 2004-2006, Kyle McMartin + 2005-2009, Faidon Liambotis + 2006-2008, Reinhard Tartler + 2006-2012, Kel Modderman + 2010, Jan Dittberner + 2010-2014, Stefan Lippers-Hollmann +License: BSD-3-clause + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License: GPL-2 + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian GNU/Linux systems, the complete text of the GNU General Public + License version 2 can be found in `/usr/share/common-licenses/GPL-2'. + . + Note that this distribution of hostapd comes with configuration options that + link it to the OpenSSL library. The OpenSSL license is GPL-incompatible, + therefore in this distribution only the BSD license applies. + +License: ISC + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + . + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +License: public-domain + Minimal code for RSA support from LibTomMath 0.41 + http://libtom.org/ + http://libtom.org/files/ltm-0.41.tar.bz2 + This library was released in public domain by Tom St Denis. + . + The combination in this file may not use all of the optimized algorithms + from LibTomMath and may be considerable slower than the LibTomMath with its + default settings. The main purpose of having this version here is to make it + easier to build bignum.c wrapper without having to install and build an + external library. + diff --git a/extras-buildpkgs/hostapd-realtek/debian/get-orig-source b/extras-buildpkgs/hostapd-realtek/debian/get-orig-source new file mode 100644 index 0000000000..aa7a389c88 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/get-orig-source @@ -0,0 +1,92 @@ +#!/bin/sh +set -e + +if [ -n "${1}" ]; then + CURDIR="${1}" +else + echo "ERROR: not called with \$(CURDIR) parameter" >&2 + exit 1 +fi + +# parse versions +VERSION="$(dpkg-parsechangelog -l${CURDIR}/debian/changelog | sed -ne 's,^Version: *\([0-9]*:\)\?\(.*\)$,\2,p')" +DEB_VER="$(echo ${VERSION} | sed 's,\-[0-9a-z\~\.]*,,')" +UP_VER="$(echo ${DEB_VER} | sed 's,\~,\-,g')" +SNAPDATE="$(echo ${DEB_VER} | sed 's/.*\+git\([0-9]*\).*/\1/')" + +case "${UP_VER}" in +*+git[0-9\.]*+*) + UP_VER_TAG="$(echo $UP_VER | sed 's,.*+git[0-9\.]*+,,')" + ;; +*) + UP_VER_TAG="hostap_$(echo $UP_VER | sed -e 's,\.,_,g' -e 's,\-,_,g')" + ;; +esac + +# set upstream (git-) Vcs +UP_VCS="git://w1.fi/srv/git/hostap.git" +if dpkg --compare-versions "${DEB_VER}" lt "2~"; then + UP_VCS="git://w1.fi/srv/git/hostap-1.git" +fi + +# write to ../{,_}tarballs/, if it exists - ../ otherwise +if [ -d "${CURDIR}/../tarballs" ]; then + ORIG_TARBALL="${CURDIR}/../tarballs/wpa_${DEB_VER}.orig.tar.xz" +elif [ -d "${CURDIR}/../_tarballs" ]; then + ORIG_TARBALL="${CURDIR}/../_tarballs/wpa_${DEB_VER}.orig.tar.xz" +else + ORIG_TARBALL="${CURDIR}/../wpa_${DEB_VER}.orig.tar.xz" +fi + +# don't overwrite existing tarballs +if [ -e "${ORIG_TARBALL}" ]; then + echo "ERROR: don't overwrite existing ${ORIG_TARBALL}" >&2 + exit 2 +fi + +TEMP_SOURCE="$(mktemp -d --tmpdir wpa-orig-source.XXXXXXXXXX)" +if [ "$?" -ne 0 ] || [ -z "${TEMP_SOURCE}" ] || [ ! -d "${TEMP_SOURCE}" ]; then + echo "ERROR: failed to create temporary working directory" >&2 + exit 3 +fi + +# clone upstream git repository +echo "clone ${UP_VCS}:" +git clone "${UP_VCS}" "${TEMP_SOURCE}" +if [ "$?" -ne 0 ] || [ ! -d "${TEMP_SOURCE}" ]; then + echo "ERROR: cloning ${UP_VCS} failed" >&2 + rm -rf "${TEMP_SOURCE}" + exit 4 +fi + +# add CONTRIBUTIONS for wpa 2.2~ +# (it's available since 2.0~, but only gets included in 2.2~) +if dpkg --compare-versions "${DEB_VER}" ge "2.2~"; then + CONTRIBUTIONS="CONTRIBUTIONS" +fi + +# add Hotspot 2.0 OSU server for wpa 2.2~ +if dpkg --compare-versions "${DEB_VER}" ge "2.2~"; then + HS20="hs20" +elif dpkg --compare-versions "${DEB_VER}" ge "2.1+" && [ "${SNAPDATE}" -ge "20140526" ]; then + HS20="hs20" +fi + +# create new upstream tarball +cd "${TEMP_SOURCE}" && \ + git archive \ + --format=tar \ + --prefix="wpa-${UP_VER}/" \ + "${UP_VER_TAG}" \ + README COPYING $CONTRIBUTIONS patches src wpa_supplicant hostapd $HS20 | \ + xz -c6 > "${ORIG_TARBALL}" +if [ "$?" -ne 0 ] || [ ! -e "${ORIG_TARBALL}" ]; then + echo "ERROR: failure to create ${ORIG_TARBALL}" >&2 + rm -rf "${TEMP_SOURCE}" + exit 5 +else + echo "SUCCESS: New upstream tarball has been saved at ${ORIG_TARBALL}" + rm -rf "${TEMP_SOURCE}" + exit 0 +fi + diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.README.Debian b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.README.Debian new file mode 100644 index 0000000000..3218a613f6 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.README.Debian @@ -0,0 +1,38 @@ +hostapd for Debian +------------------ + +This package provides two methods for managing hostapd process(es); an +initscript and an ifupdown hook. Both methods require creation of a +hostapd daemon configuration file (eg. /etc/hostapd/hostapd.conf) to +function correctly. + +An example hostapd.conf may be used as a template but _must_ be edited +to suit your local configuration. An example is located at: + /usr/share/doc/hostapd/examples/hostapd.conf.gz + +To use the example as a template: + # zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > \ + /etc/hostapd/hostapd.conf + # $EDITOR /etc/hostapd/hostapd.conf + +To use the initscript method of starting a hostapd daemon see +/etc/default/hostapd. + +To use the ifupdown method, the path to hostapd configuration file can +be specified in a network interfaces configuration stanza in +/etc/network/interfaces like so: + +iface eth1 inet static + hostapd /etc/hostapd/hostapd.conf + ... + +The hostapd process will be started in the pre-up phase of ifup, and be +terminated in the post-down phase of ifdown. + + -- Kel Modderman Tue, 27 Oct 2009 12:03:01 +1000 + +Please note: +* If you want to use hostapd with a Prism2/2.5/3 card in WPA mode, you'll need + STA firmware version >= 1.7.0. + + -- Faidon Liambotis , Mon, 10 Oct 2005 14:57:11 +0300 diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.default b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.default new file mode 100644 index 0000000000..1e12174c29 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.default @@ -0,0 +1,20 @@ +# Defaults for hostapd initscript +# +# See /usr/share/doc/hostapd/README.Debian for information about alternative +# methods of managing hostapd. +# +# Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration +# file and hostapd will be started during system boot. An example configuration +# file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz +# +#DAEMON_CONF="" + +# Additional daemon options to be appended to hostapd command:- +# -d show more debug messages (-dd for even more) +# -K include key data in debug messages +# -t include timestamps in some debug messages +# +# Note that -B (daemon mode) and -P (pidfile) options are automatically +# configured by the init.d script and must not be added to DAEMON_OPTS. +# +#DAEMON_OPTS="" diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.examples b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.examples new file mode 100644 index 0000000000..a02eefc9fb --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.examples @@ -0,0 +1,6 @@ +hostapd/hostapd.accept +hostapd/hostapd.conf +hostapd/hostapd.deny +hostapd/hostapd.eap_user +hostapd/hostapd.radius_clients +hostapd/hostapd.wpa_psk diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.init b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.init new file mode 100644 index 0000000000..548840c6ae --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.init @@ -0,0 +1,67 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: hostapd +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Should-Start: $network +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Advanced IEEE 802.11 management daemon +# Description: Userspace IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP +# Authenticator +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON_SBIN=/usr/sbin/hostapd +DAEMON_DEFS=/etc/default/hostapd +DAEMON_CONF= +NAME=hostapd +DESC="advanced IEEE 802.11 management" +PIDFILE=/run/hostapd.pid + +[ -x "$DAEMON_SBIN" ] || exit 0 +[ -s "$DAEMON_DEFS" ] && . /etc/default/hostapd +[ -n "$DAEMON_CONF" ] || exit 0 + +DAEMON_OPTS="-B -P $PIDFILE $DAEMON_OPTS $DAEMON_CONF" + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + start-stop-daemon --start --oknodo --quiet --exec "$DAEMON_SBIN" \ + --pidfile "$PIDFILE" -- $DAEMON_OPTS >/dev/null + log_end_msg "$?" + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \ + --pidfile "$PIDFILE" + log_end_msg "$?" + ;; + reload) + log_daemon_msg "Reloading $DESC" "$NAME" + start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \ + --pidfile "$PIDFILE" + log_end_msg "$?" + ;; + restart|force-reload) + $0 stop + sleep 8 + $0 start + ;; + status) + status_of_proc "$DAEMON_SBIN" "$NAME" + exit $? + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.install b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.install new file mode 100644 index 0000000000..5db606f8e9 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.install @@ -0,0 +1,2 @@ +hostapd/hostapd usr/sbin/ +hostapd/hostapd_cli usr/sbin/ diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.links b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.links new file mode 100644 index 0000000000..471b6f50ec --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.links @@ -0,0 +1,2 @@ +etc/hostapd/ifupdown.sh /etc/network/if-pre-up.d/hostapd +etc/hostapd/ifupdown.sh /etc/network/if-post-down.d/hostapd diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.manpages b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.manpages new file mode 100644 index 0000000000..ef6882fa02 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.manpages @@ -0,0 +1,2 @@ +hostapd/hostapd.8 +hostapd/hostapd_cli.1 diff --git a/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.preinst b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.preinst new file mode 100644 index 0000000000..af53de4762 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/hostapd-realtek.preinst @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +rm_conffile() { + local PKGNAME="$1" + local CONFFILE="$2" + + [ -e "$CONFFILE" ] || return 0 + + local md5sum="$(md5sum $CONFFILE | sed -e 's/ .*//')" + local old_md5sum="$(dpkg-query -W -f='${Conffiles}' $PKGNAME | \ + sed -n -e "\' $CONFFILE ' { s/ obsolete$//; s/.* //; p }")" + if [ "$md5sum" = "$old_md5sum" ]; then + echo "Removing obsolete conffile $CONFFILE ..." + rm -f "$CONFFILE" + fi +} + +case "$1" in + install|upgrade) + if dpkg --compare-versions "$2" le "1:0.6.9-3"; then + rm_conffile hostapd /etc/hostapd/hostapd.conf + fi + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/extras-buildpkgs/hostapd-realtek/debian/ifupdown/hostapd.sh b/extras-buildpkgs/hostapd-realtek/debian/ifupdown/hostapd.sh new file mode 100644 index 0000000000..c5d235776a --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/ifupdown/hostapd.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +# Copyright (C) 2006-2009 Debian hostapd maintainers +# Faidon Liambotis +# Kel Modderman +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# On Debian GNU/Linux systems, the text of the GPL license, +# version 2, can be found in /usr/share/common-licenses/GPL-2. + +# quit if we're called for lo +if [ "$IFACE" = lo ]; then + exit 0 +fi + +if [ -n "$IF_HOSTAPD" ]; then + HOSTAPD_CONF="$IF_HOSTAPD" +else + exit 0 +fi + +HOSTAPD_BIN="/usr/sbin/hostapd" +HOSTAPD_PNAME="hostapd" +HOSTAPD_PIDFILE="/run/hostapd.$IFACE.pid" +HOSTAPD_OMIT_PIDFILE="/run/sendsigs.omit.d/hostapd.$IFACE.pid" + +if [ ! -x "$HOSTAPD_BIN" ]; then + exit 0 +fi + +if [ "$VERBOSITY" = "1" ]; then + TO_NULL="/dev/stdout" +else + TO_NULL="/dev/null" +fi + +hostapd_msg () { + case "$1" in + verbose) + shift + echo "$HOSTAPD_PNAME: $@" > "$TO_NULL" + ;; + stderr) + shift + echo "$HOSTAPD_PNAME: $@" > /dev/stderr + ;; + *) + ;; + esac +} + +test_hostapd_pidfile () { + if [ -n "$1" ] && [ -f "$2" ]; then + if start-stop-daemon --stop --quiet --signal 0 \ + --exec "$1" --pidfile "$2"; then + return 0 + else + rm -f "$2" + return 1 + fi + else + return 1 + fi +} + +init_hostapd () { + HOSTAPD_OPTIONS="-B -P $HOSTAPD_PIDFILE $HOSTAPD_CONF" + HOSTAPD_MESSAGE="$HOSTAPD_BIN $HOSTAPD_OPTIONS" + + test_hostapd_pidfile "$HOSTAPD_BIN" "$HOSTAPD_PIDFILE" && return 0 + + hostapd_msg verbose "$HOSTAPD_MESSAGE" + start-stop-daemon --start --oknodo --quiet --exec "$HOSTAPD_BIN" \ + --pidfile "$HOSTAPD_PIDFILE" -- $HOSTAPD_OPTIONS > "$TO_NULL" + + if [ "$?" -ne 0 ]; then + return "$?" + fi + + HOSTAPD_PIDFILE_WAIT=0 + until [ -s "$HOSTAPD_PIDFILE" ]; do + if [ "$HOSTAPD_PIDFILE_WAIT" -ge 5 ]; then + hostapd_msg stderr \ + "timeout waiting for pid file creation" + return 1 + fi + + HOSTAPD_PIDFILE_WAIT=$(($HOSTAPD_PIDFILE_WAIT + 1)) + sleep 1 + done + cat "$HOSTAPD_PIDFILE" > "$HOSTAPD_OMIT_PIDFILE" + + return 0 +} + +kill_hostapd () { + HOSTAPD_MESSAGE="stopping $HOSTAPD_PNAME via pidfile: $HOSTAPD_PIDFILE" + + test_hostapd_pidfile "$HOSTAPD_BIN" "$HOSTAPD_PIDFILE" || return 0 + + hostapd_msg verbose "$HOSTAPD_MESSAGE" + start-stop-daemon --stop --oknodo --quiet --exec "$HOSTAPD_BIN" \ + --pidfile "$HOSTAPD_PIDFILE" > "$TO_NULL" + + [ "$HOSTAPD_OMIT_PIDFILE" ] && rm -f "$HOSTAPD_OMIT_PIDFILE" +} + +case "$MODE" in + start) + case "$PHASE" in + pre-up) + init_hostapd || exit 1 + ;; + *) + hostapd_msg stderr "unknown phase: \"$PHASE\"" + exit 1 + ;; + esac + ;; + stop) + case "$PHASE" in + post-down) + kill_hostapd + ;; + *) + hostapd_msg stderr "unknown phase: \"$PHASE\"" + exit 1 + ;; + esac + ;; + *) + hostapd_msg stderr "unknown mode: \"$MODE\"" + exit 1 + ;; +esac + +exit 0 diff --git a/extras-buildpkgs/hostapd-realtek/debian/patches/300-noscan.patch b/extras-buildpkgs/hostapd-realtek/debian/patches/300-noscan.patch new file mode 100644 index 0000000000..fba0bf32f3 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/patches/300-noscan.patch @@ -0,0 +1,62 @@ +diff --git a/hostapd/config_file.c b/hostapd/config_file.c +index 82ac61d..3570d96 100644 +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2795,6 +2795,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, + } + #endif /* CONFIG_IEEE80211W */ + #ifdef CONFIG_IEEE80211N ++ } else if (os_strcmp(buf, "noscan") == 0) { ++ conf->noscan = atoi(pos); + } else if (os_strcmp(buf, "ieee80211n") == 0) { + conf->ieee80211n = atoi(pos); + } else if (os_strcmp(buf, "ht_capab") == 0) { +diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h +index de470a9..f2a0235 100644 +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -626,6 +626,7 @@ struct hostapd_config { + + int ht_op_mode_fixed; + u16 ht_capab; ++ int noscan; + int ieee80211n; + int secondary_channel; + int no_pri_sec_switch; +diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c +index fc8786d..0d5b384 100644 +--- a/src/ap/hw_features.c ++++ b/src/ap/hw_features.c +@@ -472,7 +472,7 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) + struct wpa_driver_scan_params params; + int ret; + +- if (!iface->conf->secondary_channel) ++ if (!iface->conf->secondary_channel || iface->conf->noscan) + return 0; /* HT40 not used */ + + hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); +diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c +index 11fde2a..87fb67b 100644 +--- a/src/ap/ieee802_11_ht.c ++++ b/src/ap/ieee802_11_ht.c +@@ -221,6 +221,9 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, + if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) + return; + ++ if (iface->conf->noscan) ++ return; ++ + if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) + return; + +@@ -345,6 +348,9 @@ void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta) + if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) + return; + ++ if (iface->conf->noscan) ++ return; ++ + wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR + " in Association Request", MAC2STR(sta->addr)); + diff --git a/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch b/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch new file mode 100644 index 0000000000..c4cc7ecda8 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/patches/realtek.patch @@ -0,0 +1,11565 @@ +diff --git a/hostapd/main.c b/hostapd/main.c +index 6c7406a..07dda78 100644 +--- a/hostapd/main.c ++++ b/hostapd/main.c +@@ -422,7 +422,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, + static void show_version(void) + { + fprintf(stderr, +- "hostapd v" VERSION_STR "\n" ++ "hostapd v" VERSION_STR " for Realtek rtl871xdrv\n" + "User space daemon for IEEE 802.11 AP management,\n" + "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" + "Copyright (c) 2002-2015, Jouni Malinen " +diff --git a/hostapd/main.c.orig b/hostapd/main.c.orig +new file mode 100644 +index 0000000..6c7406a +--- /dev/null ++++ b/hostapd/main.c.orig +@@ -0,0 +1,805 @@ ++/* ++ * hostapd / main() ++ * Copyright (c) 2002-2015, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++#ifndef CONFIG_NATIVE_WINDOWS ++#include ++#include ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++#include "utils/common.h" ++#include "utils/eloop.h" ++#include "utils/uuid.h" ++#include "crypto/random.h" ++#include "crypto/tls.h" ++#include "common/version.h" ++#include "drivers/driver.h" ++#include "eap_server/eap.h" ++#include "eap_server/tncs.h" ++#include "ap/hostapd.h" ++#include "ap/ap_config.h" ++#include "ap/ap_drv_ops.h" ++#include "fst/fst.h" ++#include "config_file.h" ++#include "eap_register.h" ++#include "ctrl_iface.h" ++ ++ ++struct hapd_global { ++ void **drv_priv; ++ size_t drv_count; ++}; ++ ++static struct hapd_global global; ++ ++ ++#ifndef CONFIG_NO_HOSTAPD_LOGGER ++static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, ++ int level, const char *txt, size_t len) ++{ ++ struct hostapd_data *hapd = ctx; ++ char *format, *module_str; ++ int maxlen; ++ int conf_syslog_level, conf_stdout_level; ++ unsigned int conf_syslog, conf_stdout; ++ ++ maxlen = len + 100; ++ format = os_malloc(maxlen); ++ if (!format) ++ return; ++ ++ if (hapd && hapd->conf) { ++ conf_syslog_level = hapd->conf->logger_syslog_level; ++ conf_stdout_level = hapd->conf->logger_stdout_level; ++ conf_syslog = hapd->conf->logger_syslog; ++ conf_stdout = hapd->conf->logger_stdout; ++ } else { ++ conf_syslog_level = conf_stdout_level = 0; ++ conf_syslog = conf_stdout = (unsigned int) -1; ++ } ++ ++ switch (module) { ++ case HOSTAPD_MODULE_IEEE80211: ++ module_str = "IEEE 802.11"; ++ break; ++ case HOSTAPD_MODULE_IEEE8021X: ++ module_str = "IEEE 802.1X"; ++ break; ++ case HOSTAPD_MODULE_RADIUS: ++ module_str = "RADIUS"; ++ break; ++ case HOSTAPD_MODULE_WPA: ++ module_str = "WPA"; ++ break; ++ case HOSTAPD_MODULE_DRIVER: ++ module_str = "DRIVER"; ++ break; ++ case HOSTAPD_MODULE_IAPP: ++ module_str = "IAPP"; ++ break; ++ case HOSTAPD_MODULE_MLME: ++ module_str = "MLME"; ++ break; ++ default: ++ module_str = NULL; ++ break; ++ } ++ ++ if (hapd && hapd->conf && addr) ++ os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", ++ hapd->conf->iface, MAC2STR(addr), ++ module_str ? " " : "", module_str ? module_str : "", ++ txt); ++ else if (hapd && hapd->conf) ++ os_snprintf(format, maxlen, "%s:%s%s %s", ++ hapd->conf->iface, module_str ? " " : "", ++ module_str ? module_str : "", txt); ++ else if (addr) ++ os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", ++ MAC2STR(addr), module_str ? " " : "", ++ module_str ? module_str : "", txt); ++ else ++ os_snprintf(format, maxlen, "%s%s%s", ++ module_str ? module_str : "", ++ module_str ? ": " : "", txt); ++ ++ if ((conf_stdout & module) && level >= conf_stdout_level) { ++ wpa_debug_print_timestamp(); ++ wpa_printf(MSG_INFO, "%s", format); ++ } ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ if ((conf_syslog & module) && level >= conf_syslog_level) { ++ int priority; ++ switch (level) { ++ case HOSTAPD_LEVEL_DEBUG_VERBOSE: ++ case HOSTAPD_LEVEL_DEBUG: ++ priority = LOG_DEBUG; ++ break; ++ case HOSTAPD_LEVEL_INFO: ++ priority = LOG_INFO; ++ break; ++ case HOSTAPD_LEVEL_NOTICE: ++ priority = LOG_NOTICE; ++ break; ++ case HOSTAPD_LEVEL_WARNING: ++ priority = LOG_WARNING; ++ break; ++ default: ++ priority = LOG_INFO; ++ break; ++ } ++ syslog(priority, "%s", format); ++ } ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++ os_free(format); ++} ++#endif /* CONFIG_NO_HOSTAPD_LOGGER */ ++ ++ ++/** ++ * hostapd_driver_init - Preparate driver interface ++ */ ++static int hostapd_driver_init(struct hostapd_iface *iface) ++{ ++ struct wpa_init_params params; ++ size_t i; ++ struct hostapd_data *hapd = iface->bss[0]; ++ struct hostapd_bss_config *conf = hapd->conf; ++ u8 *b = conf->bssid; ++ struct wpa_driver_capa capa; ++ ++ if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { ++ wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); ++ return -1; ++ } ++ ++ /* Initialize the driver interface */ ++ if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) ++ b = NULL; ++ ++ os_memset(¶ms, 0, sizeof(params)); ++ for (i = 0; wpa_drivers[i]; i++) { ++ if (wpa_drivers[i] != hapd->driver) ++ continue; ++ ++ if (global.drv_priv[i] == NULL && ++ wpa_drivers[i]->global_init) { ++ global.drv_priv[i] = wpa_drivers[i]->global_init(); ++ if (global.drv_priv[i] == NULL) { ++ wpa_printf(MSG_ERROR, "Failed to initialize " ++ "driver '%s'", ++ wpa_drivers[i]->name); ++ return -1; ++ } ++ } ++ ++ params.global_priv = global.drv_priv[i]; ++ break; ++ } ++ params.bssid = b; ++ params.ifname = hapd->conf->iface; ++ params.driver_params = hapd->iconf->driver_params; ++ params.use_pae_group_addr = hapd->conf->use_pae_group_addr; ++ ++ params.num_bridge = hapd->iface->num_bss; ++ params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *)); ++ if (params.bridge == NULL) ++ return -1; ++ for (i = 0; i < hapd->iface->num_bss; i++) { ++ struct hostapd_data *bss = hapd->iface->bss[i]; ++ if (bss->conf->bridge[0]) ++ params.bridge[i] = bss->conf->bridge; ++ } ++ ++ params.own_addr = hapd->own_addr; ++ ++ hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); ++ os_free(params.bridge); ++ if (hapd->drv_priv == NULL) { ++ wpa_printf(MSG_ERROR, "%s driver initialization failed.", ++ hapd->driver->name); ++ hapd->driver = NULL; ++ return -1; ++ } ++ ++ if (hapd->driver->get_capa && ++ hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { ++ struct wowlan_triggers *triggs; ++ ++ iface->drv_flags = capa.flags; ++ iface->smps_modes = capa.smps_modes; ++ iface->probe_resp_offloads = capa.probe_resp_offloads; ++ iface->extended_capa = capa.extended_capa; ++ iface->extended_capa_mask = capa.extended_capa_mask; ++ iface->extended_capa_len = capa.extended_capa_len; ++ iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; ++ ++ triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); ++ if (triggs && hapd->driver->set_wowlan) { ++ if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) ++ wpa_printf(MSG_ERROR, "set_wowlan failed"); ++ } ++ os_free(triggs); ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * hostapd_interface_init - Read configuration file and init BSS data ++ * ++ * This function is used to parse configuration file for a full interface (one ++ * or more BSSes sharing the same radio) and allocate memory for the BSS ++ * interfaces. No actiual driver operations are started. ++ */ ++static struct hostapd_iface * ++hostapd_interface_init(struct hapd_interfaces *interfaces, ++ const char *config_fname, int debug) ++{ ++ struct hostapd_iface *iface; ++ int k; ++ ++ wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); ++ iface = hostapd_init(interfaces, config_fname); ++ if (!iface) ++ return NULL; ++ iface->interfaces = interfaces; ++ ++ for (k = 0; k < debug; k++) { ++ if (iface->bss[0]->conf->logger_stdout_level > 0) ++ iface->bss[0]->conf->logger_stdout_level--; ++ } ++ ++ if (iface->conf->bss[0]->iface[0] == '\0' && ++ !hostapd_drv_none(iface->bss[0])) { ++ wpa_printf(MSG_ERROR, "Interface name not specified in %s", ++ config_fname); ++ hostapd_interface_deinit_free(iface); ++ return NULL; ++ } ++ ++ return iface; ++} ++ ++ ++/** ++ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process ++ */ ++static void handle_term(int sig, void *signal_ctx) ++{ ++ wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); ++ eloop_terminate(); ++} ++ ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ ++static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) ++{ ++ if (hostapd_reload_config(iface) < 0) { ++ wpa_printf(MSG_WARNING, "Failed to read new configuration " ++ "file - continuing with old."); ++ } ++ return 0; ++} ++ ++ ++/** ++ * handle_reload - SIGHUP handler to reload configuration ++ */ ++static void handle_reload(int sig, void *signal_ctx) ++{ ++ struct hapd_interfaces *interfaces = signal_ctx; ++ wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", ++ sig); ++ hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); ++} ++ ++ ++static void handle_dump_state(int sig, void *signal_ctx) ++{ ++ /* Not used anymore - ignore signal */ ++} ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++ ++static int hostapd_global_init(struct hapd_interfaces *interfaces, ++ const char *entropy_file) ++{ ++ int i; ++ ++ os_memset(&global, 0, sizeof(global)); ++ ++ hostapd_logger_register_cb(hostapd_logger_cb); ++ ++ if (eap_server_register_methods()) { ++ wpa_printf(MSG_ERROR, "Failed to register EAP methods"); ++ return -1; ++ } ++ ++ if (eloop_init()) { ++ wpa_printf(MSG_ERROR, "Failed to initialize event loop"); ++ return -1; ++ } ++ ++ random_init(entropy_file); ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ eloop_register_signal(SIGHUP, handle_reload, interfaces); ++ eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ eloop_register_signal_terminate(handle_term, interfaces); ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ openlog("hostapd", 0, LOG_DAEMON); ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++ for (i = 0; wpa_drivers[i]; i++) ++ global.drv_count++; ++ if (global.drv_count == 0) { ++ wpa_printf(MSG_ERROR, "No drivers enabled"); ++ return -1; ++ } ++ global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); ++ if (global.drv_priv == NULL) ++ return -1; ++ ++ return 0; ++} ++ ++ ++static void hostapd_global_deinit(const char *pid_file) ++{ ++ int i; ++ ++ for (i = 0; wpa_drivers[i] && global.drv_priv; i++) { ++ if (!global.drv_priv[i]) ++ continue; ++ wpa_drivers[i]->global_deinit(global.drv_priv[i]); ++ } ++ os_free(global.drv_priv); ++ global.drv_priv = NULL; ++ ++#ifdef EAP_SERVER_TNC ++ tncs_global_deinit(); ++#endif /* EAP_SERVER_TNC */ ++ ++ random_deinit(); ++ ++ eloop_destroy(); ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ closelog(); ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++ eap_server_unregister_methods(); ++ ++ os_daemonize_terminate(pid_file); ++} ++ ++ ++static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, ++ const char *pid_file) ++{ ++#ifdef EAP_SERVER_TNC ++ int tnc = 0; ++ size_t i, k; ++ ++ for (i = 0; !tnc && i < ifaces->count; i++) { ++ for (k = 0; k < ifaces->iface[i]->num_bss; k++) { ++ if (ifaces->iface[i]->bss[0]->conf->tnc) { ++ tnc++; ++ break; ++ } ++ } ++ } ++ ++ if (tnc && tncs_global_init() < 0) { ++ wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); ++ return -1; ++ } ++#endif /* EAP_SERVER_TNC */ ++ ++ if (daemonize && os_daemonize(pid_file)) { ++ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); ++ return -1; ++ } ++ ++ eloop_run(); ++ ++ return 0; ++} ++ ++ ++static void show_version(void) ++{ ++ fprintf(stderr, ++ "hostapd v" VERSION_STR "\n" ++ "User space daemon for IEEE 802.11 AP management,\n" ++ "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" ++ "Copyright (c) 2002-2015, Jouni Malinen " ++ "and contributors\n"); ++} ++ ++ ++static void usage(void) ++{ ++ show_version(); ++ fprintf(stderr, ++ "\n" ++ "usage: hostapd [-hdBKtv] [-P ] [-e ] " ++ "\\\n" ++ " [-g ] [-G ] \\\n" ++ " \n" ++ "\n" ++ "options:\n" ++ " -h show this usage\n" ++ " -d show more debug messages (-dd for even more)\n" ++ " -B run daemon in the background\n" ++ " -e entropy file\n" ++ " -g global control interface path\n" ++ " -G group for control interfaces\n" ++ " -P PID file\n" ++ " -K include key data in debug messages\n" ++#ifdef CONFIG_DEBUG_FILE ++ " -f log output to debug file instead of stdout\n" ++#endif /* CONFIG_DEBUG_FILE */ ++#ifdef CONFIG_DEBUG_LINUX_TRACING ++ " -T = record to Linux tracing in addition to logging\n" ++ " (records all messages regardless of debug verbosity)\n" ++#endif /* CONFIG_DEBUG_LINUX_TRACING */ ++ " -t include timestamps in some debug messages\n" ++ " -v show hostapd version\n"); ++ ++ exit(1); ++} ++ ++ ++static const char * hostapd_msg_ifname_cb(void *ctx) ++{ ++ struct hostapd_data *hapd = ctx; ++ if (hapd && hapd->iconf && hapd->iconf->bss && ++ hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) ++ return hapd->iconf->bss[0]->iface; ++ return NULL; ++} ++ ++ ++static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, ++ const char *path) ++{ ++ char *pos; ++ os_free(interfaces->global_iface_path); ++ interfaces->global_iface_path = os_strdup(path); ++ if (interfaces->global_iface_path == NULL) ++ return -1; ++ pos = os_strrchr(interfaces->global_iface_path, '/'); ++ if (pos == NULL) { ++ wpa_printf(MSG_ERROR, "No '/' in the global control interface " ++ "file"); ++ os_free(interfaces->global_iface_path); ++ interfaces->global_iface_path = NULL; ++ return -1; ++ } ++ ++ *pos = '\0'; ++ interfaces->global_iface_name = pos + 1; ++ ++ return 0; ++} ++ ++ ++static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, ++ const char *group) ++{ ++#ifndef CONFIG_NATIVE_WINDOWS ++ struct group *grp; ++ grp = getgrnam(group); ++ if (grp == NULL) { ++ wpa_printf(MSG_ERROR, "Unknown group '%s'", group); ++ return -1; ++ } ++ interfaces->ctrl_iface_group = grp->gr_gid; ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_WPS ++static int gen_uuid(const char *txt_addr) ++{ ++ u8 addr[ETH_ALEN]; ++ u8 uuid[UUID_LEN]; ++ char buf[100]; ++ ++ if (hwaddr_aton(txt_addr, addr) < 0) ++ return -1; ++ ++ uuid_gen_mac_addr(addr, uuid); ++ if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0) ++ return -1; ++ ++ printf("%s\n", buf); ++ ++ return 0; ++} ++#endif /* CONFIG_WPS */ ++ ++ ++#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; ++ int ret = 1; ++ size_t i, j; ++ int c, debug = 0, daemonize = 0; ++ char *pid_file = NULL; ++ const char *log_file = NULL; ++ const char *entropy_file = NULL; ++ char **bss_config = NULL, **tmp_bss; ++ size_t num_bss_configs = 0; ++#ifdef CONFIG_DEBUG_LINUX_TRACING ++ int enable_trace_dbg = 0; ++#endif /* CONFIG_DEBUG_LINUX_TRACING */ ++ ++ if (os_program_init()) ++ return -1; ++ ++ os_memset(&interfaces, 0, sizeof(interfaces)); ++ interfaces.reload_config = hostapd_reload_config; ++ interfaces.config_read_cb = hostapd_config_read; ++ interfaces.for_each_interface = hostapd_for_each_interface; ++ interfaces.ctrl_iface_init = hostapd_ctrl_iface_init; ++ interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit; ++ interfaces.driver_init = hostapd_driver_init; ++ 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:"); ++ if (c < 0) ++ break; ++ switch (c) { ++ case 'h': ++ usage(); ++ break; ++ case 'd': ++ debug++; ++ if (wpa_debug_level > 0) ++ wpa_debug_level--; ++ break; ++ case 'B': ++ daemonize++; ++ break; ++ case 'e': ++ entropy_file = optarg; ++ break; ++ case 'f': ++ log_file = optarg; ++ break; ++ case 'K': ++ wpa_debug_show_keys++; ++ break; ++ case 'P': ++ os_free(pid_file); ++ pid_file = os_rel2abs_path(optarg); ++ break; ++ case 't': ++ wpa_debug_timestamp++; ++ break; ++#ifdef CONFIG_DEBUG_LINUX_TRACING ++ case 'T': ++ enable_trace_dbg = 1; ++ break; ++#endif /* CONFIG_DEBUG_LINUX_TRACING */ ++ case 'v': ++ show_version(); ++ exit(1); ++ break; ++ case 'g': ++ if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) ++ return -1; ++ break; ++ case 'G': ++ if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) ++ return -1; ++ break; ++ case 'b': ++ tmp_bss = os_realloc_array(bss_config, ++ num_bss_configs + 1, ++ sizeof(char *)); ++ if (tmp_bss == NULL) ++ goto out; ++ bss_config = tmp_bss; ++ bss_config[num_bss_configs++] = optarg; ++ break; ++#ifdef CONFIG_WPS ++ case 'u': ++ return gen_uuid(optarg); ++#endif /* CONFIG_WPS */ ++ default: ++ usage(); ++ break; ++ } ++ } ++ ++ if (optind == argc && interfaces.global_iface_path == NULL && ++ num_bss_configs == 0) ++ usage(); ++ ++ wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); ++ ++ if (log_file) ++ wpa_debug_open_file(log_file); ++ else ++ wpa_debug_setup_stdout(); ++#ifdef CONFIG_DEBUG_LINUX_TRACING ++ if (enable_trace_dbg) { ++ int tret = wpa_debug_open_linux_tracing(); ++ if (tret) { ++ wpa_printf(MSG_ERROR, "Failed to enable trace logging"); ++ return -1; ++ } ++ } ++#endif /* CONFIG_DEBUG_LINUX_TRACING */ ++ ++ interfaces.count = argc - optind; ++ if (interfaces.count || num_bss_configs) { ++ interfaces.iface = os_calloc(interfaces.count + num_bss_configs, ++ sizeof(struct hostapd_iface *)); ++ if (interfaces.iface == NULL) { ++ wpa_printf(MSG_ERROR, "malloc failed"); ++ return -1; ++ } ++ } ++ ++ if (hostapd_global_init(&interfaces, entropy_file)) { ++ 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, ++ argv[optind + i], ++ debug); ++ if (!interfaces.iface[i]) { ++ wpa_printf(MSG_ERROR, "Failed to initialize interface"); ++ goto out; ++ } ++ } ++ ++ /* Allocate and parse configuration for per-BSS files */ ++ for (i = 0; i < num_bss_configs; i++) { ++ struct hostapd_iface *iface; ++ char *fname; ++ ++ wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); ++ fname = os_strchr(bss_config[i], ':'); ++ if (fname == NULL) { ++ wpa_printf(MSG_ERROR, ++ "Invalid BSS config identifier '%s'", ++ bss_config[i]); ++ goto out; ++ } ++ *fname++ = '\0'; ++ iface = hostapd_interface_init_bss(&interfaces, bss_config[i], ++ fname, debug); ++ if (iface == NULL) ++ goto out; ++ for (j = 0; j < interfaces.count; j++) { ++ if (interfaces.iface[j] == iface) ++ break; ++ } ++ if (j == interfaces.count) { ++ struct hostapd_iface **tmp; ++ tmp = os_realloc_array(interfaces.iface, ++ interfaces.count + 1, ++ sizeof(struct hostapd_iface *)); ++ if (tmp == NULL) { ++ hostapd_interface_deinit_free(iface); ++ goto out; ++ } ++ interfaces.iface = tmp; ++ interfaces.iface[interfaces.count++] = iface; ++ } ++ } ++ ++ /* ++ * Enable configured interfaces. Depending on channel configuration, ++ * this may complete full initialization before returning or use a ++ * callback mechanism to complete setup in case of operations like HT ++ * co-ex scans, ACS, or DFS are needed to determine channel parameters. ++ * In such case, the interface will be enabled from eloop context within ++ * hostapd_global_run(). ++ */ ++ interfaces.terminate_on_error = interfaces.count; ++ for (i = 0; i < interfaces.count; i++) { ++ if (hostapd_driver_init(interfaces.iface[i]) || ++ hostapd_setup_interface(interfaces.iface[i])) ++ goto out; ++ } ++ ++ hostapd_global_ctrl_iface_init(&interfaces); ++ ++ if (hostapd_global_run(&interfaces, daemonize, pid_file)) { ++ wpa_printf(MSG_ERROR, "Failed to start eloop"); ++ goto out; ++ } ++ ++ ret = 0; ++ ++ out: ++ hostapd_global_ctrl_iface_deinit(&interfaces); ++ /* Deinitialize all interfaces */ ++ for (i = 0; i < interfaces.count; i++) { ++ if (!interfaces.iface[i]) ++ continue; ++ interfaces.iface[i]->driver_ap_teardown = ++ !!(interfaces.iface[i]->drv_flags & ++ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); ++ hostapd_interface_deinit_free(interfaces.iface[i]); ++ } ++ os_free(interfaces.iface); ++ ++ eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL); ++ hostapd_global_deinit(pid_file); ++ os_free(pid_file); ++ ++ if (log_file) ++ wpa_debug_close_file(); ++ wpa_debug_close_linux_tracing(); ++ ++ os_free(bss_config); ++ ++ fst_global_deinit(); ++ ++ os_program_deinit(); ++ ++ return ret; ++} +diff --git a/src/ap/beacon.c b/src/ap/beacon.c +index 5fe8fd5..5f7c077 100644 +--- a/src/ap/beacon.c ++++ b/src/ap/beacon.c +@@ -1007,6 +1007,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, + #ifdef CONFIG_IEEE80211N + tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); + tailpos = hostapd_eid_ht_operation(hapd, tailpos); ++ ++ //DRIVER_RTW ADD ++ if(hapd->iconf->ieee80211n) ++ hapd->conf->wmm_enabled = 1; ++ + #endif /* CONFIG_IEEE80211N */ + + tailpos = hostapd_eid_ext_capab(hapd, tailpos); +diff --git a/src/ap/beacon.c.orig b/src/ap/beacon.c.orig +new file mode 100644 +index 0000000..5fe8fd5 +--- /dev/null ++++ b/src/ap/beacon.c.orig +@@ -0,0 +1,1253 @@ ++/* ++ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response ++ * Copyright (c) 2002-2004, Instant802 Networks, Inc. ++ * Copyright (c) 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2008-2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++ ++#ifndef CONFIG_NATIVE_WINDOWS ++ ++#include "utils/common.h" ++#include "common/ieee802_11_defs.h" ++#include "common/ieee802_11_common.h" ++#include "common/hw_features_common.h" ++#include "wps/wps_defs.h" ++#include "p2p/p2p.h" ++#include "hostapd.h" ++#include "ieee802_11.h" ++#include "wpa_auth.h" ++#include "wmm.h" ++#include "ap_config.h" ++#include "sta_info.h" ++#include "p2p_hostapd.h" ++#include "ap_drv_ops.h" ++#include "beacon.h" ++#include "hs20.h" ++#include "dfs.h" ++ ++ ++#ifdef NEED_AP_MLME ++ ++static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, ++ size_t len) ++{ ++ if (!hapd->conf->radio_measurements || len < 2 + 4) ++ return eid; ++ ++ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; ++ *eid++ = 5; ++ *eid++ = (hapd->conf->radio_measurements & BIT(0)) ? ++ WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ *eid++ = 0x00; ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) ++{ ++ if (len < 2 + 5) ++ return eid; ++ ++#ifdef CONFIG_TESTING_OPTIONS ++ if (hapd->conf->bss_load_test_set) { ++ *eid++ = WLAN_EID_BSS_LOAD; ++ *eid++ = 5; ++ os_memcpy(eid, hapd->conf->bss_load_test, 5); ++ eid += 5; ++ return eid; ++ } ++#endif /* CONFIG_TESTING_OPTIONS */ ++ if (hapd->conf->bss_load_update_period) { ++ *eid++ = WLAN_EID_BSS_LOAD; ++ *eid++ = 5; ++ WPA_PUT_LE16(eid, hapd->num_sta); ++ eid += 2; ++ *eid++ = hapd->iface->channel_utilization; ++ WPA_PUT_LE16(eid, 0); /* no available admission capabity */ ++ eid += 2; ++ } ++ return eid; ++} ++ ++ ++static u8 ieee802_11_erp_info(struct hostapd_data *hapd) ++{ ++ u8 erp = 0; ++ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) ++ return 0; ++ ++ if (hapd->iface->olbc) ++ erp |= ERP_INFO_USE_PROTECTION; ++ if (hapd->iface->num_sta_non_erp > 0) { ++ erp |= ERP_INFO_NON_ERP_PRESENT | ++ ERP_INFO_USE_PROTECTION; ++ } ++ if (hapd->iface->num_sta_no_short_preamble > 0 || ++ hapd->iconf->preamble == LONG_PREAMBLE) ++ erp |= ERP_INFO_BARKER_PREAMBLE_MODE; ++ ++ return erp; ++} ++ ++ ++static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) ++{ ++ *eid++ = WLAN_EID_DS_PARAMS; ++ *eid++ = 1; ++ *eid++ = hapd->iconf->channel; ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) ++{ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) ++ return eid; ++ ++ /* Set NonERP_present and use_protection bits if there ++ * are any associated NonERP stations. */ ++ /* TODO: use_protection bit can be set to zero even if ++ * there are NonERP stations present. This optimization ++ * might be useful if NonERP stations are "quiet". ++ * See 802.11g/D6 E-1 for recommended practice. ++ * In addition, Non ERP present might be set, if AP detects Non ERP ++ * operation on other APs. */ ++ ++ /* Add ERP Information element */ ++ *eid++ = WLAN_EID_ERP_INFO; ++ *eid++ = 1; ++ *eid++ = ieee802_11_erp_info(hapd); ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 *pos = eid; ++ u8 local_pwr_constraint = 0; ++ int dfs; ++ ++ if (hapd->iface->current_mode == NULL || ++ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) ++ return eid; ++ ++ /* Let host drivers add this IE if DFS support is offloaded */ ++ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) ++ return eid; ++ ++ /* ++ * There is no DFS support and power constraint was not directly ++ * requested by config option. ++ */ ++ if (!hapd->iconf->ieee80211h && ++ hapd->iconf->local_pwr_constraint == -1) ++ return eid; ++ ++ /* Check if DFS is required by regulatory. */ ++ dfs = hostapd_is_dfs_required(hapd->iface); ++ if (dfs < 0) { ++ wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", ++ dfs); ++ dfs = 0; ++ } ++ ++ if (dfs == 0 && hapd->iconf->local_pwr_constraint == -1) ++ return eid; ++ ++ /* ++ * ieee80211h (DFS) is enabled so Power Constraint element shall ++ * be added when running on DFS channel whenever local_pwr_constraint ++ * is configured or not. In order to meet regulations when TPC is not ++ * implemented using a transmit power that is below the legal maximum ++ * (including any mitigation factor) should help. In this case, ++ * indicate 3 dB below maximum allowed transmit power. ++ */ ++ if (hapd->iconf->local_pwr_constraint == -1) ++ local_pwr_constraint = 3; ++ ++ /* ++ * A STA that is not an AP shall use a transmit power less than or ++ * equal to the local maximum transmit power level for the channel. ++ * The local maximum transmit power can be calculated from the formula: ++ * local max TX pwr = max TX pwr - local pwr constraint ++ * Where max TX pwr is maximum transmit power level specified for ++ * channel in Country element and local pwr constraint is specified ++ * for channel in this Power Constraint element. ++ */ ++ ++ /* Element ID */ ++ *pos++ = WLAN_EID_PWR_CONSTRAINT; ++ /* Length */ ++ *pos++ = 1; ++ /* Local Power Constraint */ ++ if (local_pwr_constraint) ++ *pos++ = local_pwr_constraint; ++ else ++ *pos++ = hapd->iconf->local_pwr_constraint; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, ++ struct hostapd_channel_data *start, ++ struct hostapd_channel_data *prev) ++{ ++ if (end - pos < 3) ++ return pos; ++ ++ /* first channel number */ ++ *pos++ = start->chan; ++ /* number of channels */ ++ *pos++ = (prev->chan - start->chan) / chan_spacing + 1; ++ /* maximum transmit power level */ ++ *pos++ = start->max_tx_power; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, ++ int max_len) ++{ ++ u8 *pos = eid; ++ u8 *end = eid + max_len; ++ int i; ++ struct hostapd_hw_modes *mode; ++ struct hostapd_channel_data *start, *prev; ++ int chan_spacing = 1; ++ ++ if (!hapd->iconf->ieee80211d || max_len < 6 || ++ hapd->iface->current_mode == NULL) ++ return eid; ++ ++ *pos++ = WLAN_EID_COUNTRY; ++ pos++; /* length will be set later */ ++ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ ++ pos += 3; ++ ++ mode = hapd->iface->current_mode; ++ if (mode->mode == HOSTAPD_MODE_IEEE80211A) ++ chan_spacing = 4; ++ ++ start = prev = NULL; ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (start && prev && ++ prev->chan + chan_spacing == chan->chan && ++ start->max_tx_power == chan->max_tx_power) { ++ prev = chan; ++ continue; /* can use same entry */ ++ } ++ ++ if (start && prev) { ++ pos = hostapd_eid_country_add(pos, end, chan_spacing, ++ start, prev); ++ start = NULL; ++ } ++ ++ /* Start new group */ ++ start = prev = chan; ++ } ++ ++ if (start) { ++ pos = hostapd_eid_country_add(pos, end, chan_spacing, ++ start, prev); ++ } ++ ++ if ((pos - eid) & 1) { ++ if (end - pos < 1) ++ return eid; ++ *pos++ = 0; /* pad for 16-bit alignment */ ++ } ++ ++ eid[1] = (pos - eid) - 2; ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) ++{ ++ const u8 *ie; ++ size_t ielen; ++ ++ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); ++ if (ie == NULL || ielen > len) ++ return eid; ++ ++ os_memcpy(eid, ie, ielen); ++ return eid + ielen; ++} ++ ++ ++static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 chan; ++ ++ if (!hapd->cs_freq_params.freq) ++ return eid; ++ ++ if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) == ++ NUM_HOSTAPD_MODES) ++ return eid; ++ ++ *eid++ = WLAN_EID_CHANNEL_SWITCH; ++ *eid++ = 3; ++ *eid++ = hapd->cs_block_tx; ++ *eid++ = chan; ++ *eid++ = hapd->cs_count; ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) ++{ ++ u8 sec_ch; ++ ++ if (!hapd->cs_freq_params.sec_channel_offset) ++ return eid; ++ ++ if (hapd->cs_freq_params.sec_channel_offset == -1) ++ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; ++ else if (hapd->cs_freq_params.sec_channel_offset == 1) ++ sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; ++ else ++ return eid; ++ ++ *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; ++ *eid++ = 1; ++ *eid++ = sec_ch; ++ ++ return eid; ++} ++ ++ ++static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos, ++ u8 *start, unsigned int *csa_counter_off) ++{ ++ u8 *old_pos = pos; ++ ++ if (!csa_counter_off) ++ return pos; ++ ++ *csa_counter_off = 0; ++ pos = hostapd_eid_csa(hapd, pos); ++ ++ if (pos != old_pos) { ++ /* save an offset to the counter - should be last byte */ ++ *csa_counter_off = pos - start - 1; ++ pos = hostapd_eid_secondary_channel(hapd, pos); ++ } ++ ++ return pos; ++} ++ ++ ++static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, ++ const struct ieee80211_mgmt *req, ++ int is_p2p, size_t *resp_len) ++{ ++ struct ieee80211_mgmt *resp; ++ u8 *pos, *epos; ++ size_t buflen; ++ ++#define MAX_PROBERESP_LEN 768 ++ buflen = MAX_PROBERESP_LEN; ++#ifdef CONFIG_WPS ++ if (hapd->wps_probe_resp_ie) ++ buflen += wpabuf_len(hapd->wps_probe_resp_ie); ++#endif /* CONFIG_WPS */ ++#ifdef CONFIG_P2P ++ 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) { ++ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) + ++ 2 + sizeof(struct ieee80211_vht_operation); ++ } ++ resp = os_zalloc(buflen); ++ if (resp == NULL) ++ return NULL; ++ ++ epos = ((u8 *) resp) + MAX_PROBERESP_LEN; ++ ++ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_PROBE_RESP); ++ if (req) ++ os_memcpy(resp->da, req->sa, ETH_ALEN); ++ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); ++ ++ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); ++ resp->u.probe_resp.beacon_int = ++ host_to_le16(hapd->iconf->beacon_int); ++ ++ /* hardware or low-level driver will setup seq_ctrl and timestamp */ ++ resp->u.probe_resp.capab_info = ++ host_to_le16(hostapd_own_capab_info(hapd)); ++ ++ pos = resp->u.probe_resp.variable; ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ ++ /* Supported rates */ ++ pos = hostapd_eid_supp_rates(hapd, pos); ++ ++ /* DS Params */ ++ pos = hostapd_eid_ds_params(hapd, pos); ++ ++ pos = hostapd_eid_country(hapd, pos, epos - pos); ++ ++ /* Power Constraint element */ ++ pos = hostapd_eid_pwr_constraint(hapd, pos); ++ ++ /* ERP Information element */ ++ pos = hostapd_eid_erp_info(hapd, pos); ++ ++ /* Extended supported rates */ ++ pos = hostapd_eid_ext_supp_rates(hapd, pos); ++ ++ /* RSN, MDIE, WPA */ ++ pos = hostapd_eid_wpa(hapd, pos, epos - pos); ++ ++ pos = hostapd_eid_bss_load(hapd, pos, epos - pos); ++ ++ pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); ++ ++#ifdef CONFIG_IEEE80211N ++ pos = hostapd_eid_ht_capabilities(hapd, pos); ++ pos = hostapd_eid_ht_operation(hapd, pos); ++#endif /* CONFIG_IEEE80211N */ ++ ++ pos = hostapd_eid_ext_capab(hapd, pos); ++ ++ pos = hostapd_eid_time_adv(hapd, pos); ++ pos = hostapd_eid_time_zone(hapd, pos); ++ ++ pos = hostapd_eid_interworking(hapd, pos); ++ pos = hostapd_eid_adv_proto(hapd, pos); ++ pos = hostapd_eid_roaming_consortium(hapd, pos); ++ ++ pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, ++ &hapd->cs_c_off_proberesp); ++ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) { ++ os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies), ++ 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); ++ pos = hostapd_eid_vht_operation(hapd, pos); ++ } ++ if (hapd->conf->vendor_vht) ++ pos = hostapd_eid_vendor_vht(hapd, pos); ++#endif /* CONFIG_IEEE80211AC */ ++ ++ /* Wi-Fi Alliance WMM */ ++ pos = hostapd_eid_wmm(hapd, pos); ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { ++ os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), ++ wpabuf_len(hapd->wps_probe_resp_ie)); ++ pos += wpabuf_len(hapd->wps_probe_resp_ie); ++ } ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && ++ hapd->p2p_probe_resp_ie) { ++ os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), ++ wpabuf_len(hapd->p2p_probe_resp_ie)); ++ pos += wpabuf_len(hapd->p2p_probe_resp_ie); ++ } ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_P2P_MANAGER ++ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == ++ P2P_MANAGE) ++ pos = hostapd_eid_p2p_manage(hapd, pos); ++#endif /* CONFIG_P2P_MANAGER */ ++ ++#ifdef CONFIG_HS20 ++ pos = hostapd_eid_hs20_indication(hapd, pos); ++ pos = hostapd_eid_osen(hapd, pos); ++#endif /* CONFIG_HS20 */ ++ ++ if (hapd->conf->vendor_elements) { ++ os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements), ++ wpabuf_len(hapd->conf->vendor_elements)); ++ pos += wpabuf_len(hapd->conf->vendor_elements); ++ } ++ ++ *resp_len = pos - (u8 *) resp; ++ return (u8 *) resp; ++} ++ ++ ++enum ssid_match_result { ++ NO_SSID_MATCH, ++ EXACT_SSID_MATCH, ++ WILDCARD_SSID_MATCH ++}; ++ ++static enum ssid_match_result ssid_match(struct hostapd_data *hapd, ++ const u8 *ssid, size_t ssid_len, ++ const u8 *ssid_list, ++ size_t ssid_list_len) ++{ ++ const u8 *pos, *end; ++ int wildcard = 0; ++ ++ if (ssid_len == 0) ++ wildcard = 1; ++ if (ssid_len == hapd->conf->ssid.ssid_len && ++ os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0) ++ return EXACT_SSID_MATCH; ++ ++ if (ssid_list == NULL) ++ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; ++ ++ pos = ssid_list; ++ end = ssid_list + ssid_list_len; ++ while (pos + 1 <= end) { ++ if (pos + 2 + pos[1] > end) ++ break; ++ if (pos[1] == 0) ++ wildcard = 1; ++ if (pos[1] == hapd->conf->ssid.ssid_len && ++ os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0) ++ return EXACT_SSID_MATCH; ++ pos += 2 + pos[1]; ++ } ++ ++ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; ++} ++ ++ ++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) ++{ ++ u8 *resp; ++ struct ieee802_11_elems elems; ++ const u8 *ie; ++ size_t ie_len; ++ size_t i, resp_len; ++ int noack; ++ enum ssid_match_result res; ++ ++ ie = mgmt->u.probe_req.variable; ++ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) ++ 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++) ++ if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, ++ mgmt->sa, mgmt->da, mgmt->bssid, ++ ie, ie_len, ssi_signal) > 0) ++ return; ++ ++ if (!hapd->iconf->send_probe_response) ++ return; ++ ++ if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { ++ wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++ if ((!elems.ssid || !elems.supp_rates)) { ++ wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " ++ "without SSID or supported rates element", ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++ /* ++ * No need to reply if the Probe Request frame was sent on an adjacent ++ * channel. IEEE Std 802.11-2012 describes this as a requirement for an ++ * AP with dot11RadioMeasurementActivated set to true, but strictly ++ * speaking does not allow such ignoring of Probe Request frames if ++ * dot11RadioMeasurementActivated is false. Anyway, this can help reduce ++ * number of unnecessary Probe Response frames for cases where the STA ++ * is less likely to see them (Probe Request frame sent on a ++ * neighboring, but partially overlapping, channel). ++ */ ++ if (elems.ds_params && ++ hapd->iface->current_mode && ++ (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G || ++ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) && ++ hapd->iconf->channel != elems.ds_params[0]) { ++ wpa_printf(MSG_DEBUG, ++ "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u", ++ hapd->iconf->channel, elems.ds_params[0]); ++ return; ++ } ++ ++#ifdef CONFIG_P2P ++ if (hapd->p2p && elems.wps_ie) { ++ struct wpabuf *wps; ++ wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); ++ if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { ++ wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " ++ "due to mismatch with Requested Device " ++ "Type"); ++ wpabuf_free(wps); ++ return; ++ } ++ wpabuf_free(wps); ++ } ++ ++ if (hapd->p2p && elems.p2p) { ++ struct wpabuf *p2p; ++ p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE); ++ if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) { ++ wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " ++ "due to mismatch with Device ID"); ++ wpabuf_free(p2p); ++ return; ++ } ++ wpabuf_free(p2p); ++ } ++#endif /* CONFIG_P2P */ ++ ++ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 && ++ elems.ssid_list_len == 0) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " ++ "broadcast SSID ignored", MAC2STR(mgmt->sa)); ++ return; ++ } ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_GROUP_OWNER) && ++ elems.ssid_len == P2P_WILDCARD_SSID_LEN && ++ os_memcmp(elems.ssid, P2P_WILDCARD_SSID, ++ P2P_WILDCARD_SSID_LEN) == 0) { ++ /* Process P2P Wildcard SSID like Wildcard SSID */ ++ elems.ssid_len = 0; ++ } ++#endif /* CONFIG_P2P */ ++ ++ res = ssid_match(hapd, elems.ssid, elems.ssid_len, ++ elems.ssid_list, elems.ssid_list_len); ++ 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", ++ MAC2STR(mgmt->sa), ++ wpa_ssid_txt(elems.ssid, elems.ssid_len), ++ MAC2STR(mgmt->da), ++ elems.ssid_list ? " (SSID list)" : ""); ++ } ++ return; ++ } ++ ++#ifdef CONFIG_INTERWORKING ++ if (hapd->conf->interworking && ++ elems.interworking && elems.interworking_len >= 1) { ++ u8 ant = elems.interworking[0] & 0x0f; ++ if (ant != INTERWORKING_ANT_WILDCARD && ++ ant != hapd->conf->access_network_type) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR ++ " for mismatching ANT %u ignored", ++ MAC2STR(mgmt->sa), ant); ++ return; ++ } ++ } ++ ++ if (hapd->conf->interworking && elems.interworking && ++ (elems.interworking_len == 7 || elems.interworking_len == 9)) { ++ const u8 *hessid; ++ if (elems.interworking_len == 7) ++ hessid = elems.interworking + 1; ++ else ++ hessid = elems.interworking + 1 + 2; ++ if (!is_broadcast_ether_addr(hessid) && ++ os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { ++ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR ++ " for mismatching HESSID " MACSTR ++ " ignored", ++ MAC2STR(mgmt->sa), MAC2STR(hessid)); ++ return; ++ } ++ } ++#endif /* CONFIG_INTERWORKING */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_GROUP_OWNER) && ++ supp_rates_11b_only(&elems)) { ++ /* Indicates support for 11b rates only */ ++ wpa_printf(MSG_EXCESSIVE, "P2P: Ignore Probe Request from " ++ MACSTR " with only 802.11b rates", ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++#endif /* CONFIG_P2P */ ++ ++ /* TODO: verify that supp_rates contains at least one matching rate ++ * with AP configuration */ ++ ++ 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) { ++ wpa_printf(MSG_INFO, ++ "TESTING: ignoring probe request from " MACSTR, ++ MAC2STR(mgmt->sa)); ++ return; ++ } ++#endif /* CONFIG_TESTING_OPTIONS */ ++ ++ resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, ++ &resp_len); ++ if (resp == NULL) ++ return; ++ ++ /* ++ * If this is a broadcast probe request, apply no ack policy to avoid ++ * excessive retries. ++ */ ++ noack = !!(res == WILDCARD_SSID_MATCH && ++ is_broadcast_ether_addr(mgmt->da)); ++ ++ if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0) ++ wpa_printf(MSG_INFO, "handle_probe_req: send failed"); ++ ++ os_free(resp); ++ ++ wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " ++ "SSID", MAC2STR(mgmt->sa), ++ elems.ssid_len == 0 ? "broadcast" : "our"); ++} ++ ++ ++static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, ++ size_t *resp_len) ++{ ++ /* check probe response offloading caps and print warnings */ ++ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) ++ return NULL; ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie && ++ (!(hapd->iface->probe_resp_offloads & ++ (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS | ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2)))) ++ wpa_printf(MSG_WARNING, "Device is trying to offload WPS " ++ "Probe Response while not supporting this"); ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie && ++ !(hapd->iface->probe_resp_offloads & ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P)) ++ wpa_printf(MSG_WARNING, "Device is trying to offload P2P " ++ "Probe Response while not supporting this"); ++#endif /* CONFIG_P2P */ ++ ++ if (hapd->conf->interworking && ++ !(hapd->iface->probe_resp_offloads & ++ WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING)) ++ wpa_printf(MSG_WARNING, "Device is trying to offload " ++ "Interworking Probe Response while not supporting " ++ "this"); ++ ++ /* Generate a Probe Response template for the non-P2P case */ ++ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len); ++} ++ ++#endif /* NEED_AP_MLME */ ++ ++ ++int ieee802_11_build_ap_params(struct hostapd_data *hapd, ++ struct wpa_driver_ap_params *params) ++{ ++ struct ieee80211_mgmt *head = NULL; ++ u8 *tail = NULL; ++ size_t head_len = 0, tail_len = 0; ++ u8 *resp = NULL; ++ size_t resp_len = 0; ++#ifdef NEED_AP_MLME ++ u16 capab_info; ++ u8 *pos, *tailpos; ++ ++#define BEACON_HEAD_BUF_SIZE 256 ++#define BEACON_TAIL_BUF_SIZE 512 ++ head = os_zalloc(BEACON_HEAD_BUF_SIZE); ++ tail_len = BEACON_TAIL_BUF_SIZE; ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_beacon_ie) ++ tail_len += wpabuf_len(hapd->wps_beacon_ie); ++#endif /* CONFIG_WPS */ ++#ifdef CONFIG_P2P ++ 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); ++ ++#ifdef CONFIG_IEEE80211AC ++ if (hapd->conf->vendor_vht) { ++ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) + ++ 2 + sizeof(struct ieee80211_vht_operation); ++ } ++#endif /* CONFIG_IEEE80211AC */ ++ ++ tailpos = tail = os_malloc(tail_len); ++ if (head == NULL || tail == NULL) { ++ wpa_printf(MSG_ERROR, "Failed to set beacon data"); ++ os_free(head); ++ os_free(tail); ++ return -1; ++ } ++ ++ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_BEACON); ++ head->duration = host_to_le16(0); ++ os_memset(head->da, 0xff, ETH_ALEN); ++ ++ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); ++ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); ++ head->u.beacon.beacon_int = ++ host_to_le16(hapd->iconf->beacon_int); ++ ++ /* hardware or low-level driver will setup seq_ctrl and timestamp */ ++ capab_info = hostapd_own_capab_info(hapd); ++ head->u.beacon.capab_info = host_to_le16(capab_info); ++ pos = &head->u.beacon.variable[0]; ++ ++ /* SSID */ ++ *pos++ = WLAN_EID_SSID; ++ if (hapd->conf->ignore_broadcast_ssid == 2) { ++ /* clear the data, but keep the correct length of the SSID */ ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memset(pos, 0, hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ } else if (hapd->conf->ignore_broadcast_ssid) { ++ *pos++ = 0; /* empty SSID */ ++ } else { ++ *pos++ = hapd->conf->ssid.ssid_len; ++ os_memcpy(pos, hapd->conf->ssid.ssid, ++ hapd->conf->ssid.ssid_len); ++ pos += hapd->conf->ssid.ssid_len; ++ } ++ ++ /* Supported rates */ ++ pos = hostapd_eid_supp_rates(hapd, pos); ++ ++ /* DS Params */ ++ pos = hostapd_eid_ds_params(hapd, pos); ++ ++ head_len = pos - (u8 *) head; ++ ++ tailpos = hostapd_eid_country(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - tailpos); ++ ++ /* Power Constraint element */ ++ tailpos = hostapd_eid_pwr_constraint(hapd, tailpos); ++ ++ /* ERP Information element */ ++ tailpos = hostapd_eid_erp_info(hapd, tailpos); ++ ++ /* Extended supported rates */ ++ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); ++ ++ /* RSN, MDIE, WPA */ ++ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - ++ tailpos); ++ ++ tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - ++ tailpos); ++ ++ tailpos = hostapd_eid_bss_load(hapd, tailpos, ++ tail + BEACON_TAIL_BUF_SIZE - tailpos); ++ ++#ifdef CONFIG_IEEE80211N ++ tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); ++ tailpos = hostapd_eid_ht_operation(hapd, tailpos); ++#endif /* CONFIG_IEEE80211N */ ++ ++ tailpos = hostapd_eid_ext_capab(hapd, tailpos); ++ ++ /* ++ * TODO: Time Advertisement element should only be included in some ++ * DTIM Beacon frames. ++ */ ++ tailpos = hostapd_eid_time_adv(hapd, tailpos); ++ ++ tailpos = hostapd_eid_interworking(hapd, tailpos); ++ tailpos = hostapd_eid_adv_proto(hapd, tailpos); ++ tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); ++ tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, ++ &hapd->cs_c_off_beacon); ++ ++#ifdef CONFIG_FST ++ if (hapd->iface->fst_ies) { ++ 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); ++ tailpos = hostapd_eid_vht_operation(hapd, tailpos); ++ } ++ if (hapd->conf->vendor_vht) ++ tailpos = hostapd_eid_vendor_vht(hapd, tailpos); ++#endif /* CONFIG_IEEE80211AC */ ++ ++ /* Wi-Fi Alliance WMM */ ++ tailpos = hostapd_eid_wmm(hapd, tailpos); ++ ++#ifdef CONFIG_WPS ++ if (hapd->conf->wps_state && hapd->wps_beacon_ie) { ++ os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), ++ wpabuf_len(hapd->wps_beacon_ie)); ++ tailpos += wpabuf_len(hapd->wps_beacon_ie); ++ } ++#endif /* CONFIG_WPS */ ++ ++#ifdef CONFIG_P2P ++ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) { ++ os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie), ++ wpabuf_len(hapd->p2p_beacon_ie)); ++ tailpos += wpabuf_len(hapd->p2p_beacon_ie); ++ } ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_P2P_MANAGER ++ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == ++ P2P_MANAGE) ++ tailpos = hostapd_eid_p2p_manage(hapd, tailpos); ++#endif /* CONFIG_P2P_MANAGER */ ++ ++#ifdef CONFIG_HS20 ++ tailpos = hostapd_eid_hs20_indication(hapd, tailpos); ++ tailpos = hostapd_eid_osen(hapd, tailpos); ++#endif /* CONFIG_HS20 */ ++ ++ if (hapd->conf->vendor_elements) { ++ os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements), ++ wpabuf_len(hapd->conf->vendor_elements)); ++ tailpos += wpabuf_len(hapd->conf->vendor_elements); ++ } ++ ++ tail_len = tailpos > tail ? tailpos - tail : 0; ++ ++ resp = hostapd_probe_resp_offloads(hapd, &resp_len); ++#endif /* NEED_AP_MLME */ ++ ++ os_memset(params, 0, sizeof(*params)); ++ params->head = (u8 *) head; ++ params->head_len = head_len; ++ params->tail = tail; ++ params->tail_len = tail_len; ++ params->proberesp = resp; ++ params->proberesp_len = resp_len; ++ params->dtim_period = hapd->conf->dtim_period; ++ params->beacon_int = hapd->iconf->beacon_int; ++ params->basic_rates = hapd->iface->basic_rates; ++ params->ssid = hapd->conf->ssid.ssid; ++ params->ssid_len = hapd->conf->ssid.ssid_len; ++ 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; ++ params->wpa_version = hapd->conf->wpa; ++ params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa || ++ (hapd->conf->ieee802_1x && ++ (hapd->conf->default_wep_key_len || ++ hapd->conf->individual_wep_key_len)); ++ switch (hapd->conf->ignore_broadcast_ssid) { ++ case 0: ++ params->hide_ssid = NO_SSID_HIDING; ++ break; ++ case 1: ++ params->hide_ssid = HIDDEN_SSID_ZERO_LEN; ++ break; ++ case 2: ++ params->hide_ssid = HIDDEN_SSID_ZERO_CONTENTS; ++ break; ++ } ++ params->isolate = hapd->conf->isolate; ++ params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK; ++#ifdef NEED_AP_MLME ++ params->cts_protect = !!(ieee802_11_erp_info(hapd) & ++ ERP_INFO_USE_PROTECTION); ++ params->preamble = hapd->iface->num_sta_no_short_preamble == 0 && ++ hapd->iconf->preamble == SHORT_PREAMBLE; ++ if (hapd->iface->current_mode && ++ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ params->short_slot_time = ++ hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1; ++ else ++ params->short_slot_time = -1; ++ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) ++ params->ht_opmode = -1; ++ else ++ params->ht_opmode = hapd->iface->ht_op_mode; ++#endif /* NEED_AP_MLME */ ++ params->interworking = hapd->conf->interworking; ++ if (hapd->conf->interworking && ++ !is_zero_ether_addr(hapd->conf->hessid)) ++ params->hessid = hapd->conf->hessid; ++ params->access_network_type = hapd->conf->access_network_type; ++ params->ap_max_inactivity = hapd->conf->ap_max_inactivity; ++#ifdef CONFIG_P2P ++ params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow; ++#endif /* CONFIG_P2P */ ++#ifdef CONFIG_HS20 ++ params->disable_dgaf = hapd->conf->disable_dgaf; ++ if (hapd->conf->osen) { ++ params->privacy = 1; ++ params->osen = 1; ++ } ++#endif /* CONFIG_HS20 */ ++ return 0; ++} ++ ++ ++void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) ++{ ++ os_free(params->tail); ++ params->tail = NULL; ++ os_free(params->head); ++ params->head = NULL; ++ os_free(params->proberesp); ++ params->proberesp = NULL; ++} ++ ++ ++int ieee802_11_set_beacon(struct hostapd_data *hapd) ++{ ++ struct wpa_driver_ap_params params; ++ struct hostapd_freq_params freq; ++ struct hostapd_iface *iface = hapd->iface; ++ struct hostapd_config *iconf = iface->conf; ++ struct wpabuf *beacon, *proberesp, *assocresp; ++ int res, ret = -1; ++ ++ if (hapd->csa_in_progress) { ++ wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); ++ return -1; ++ } ++ ++ hapd->beacon_set_done = 1; ++ ++ if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) ++ return -1; ++ ++ if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) < ++ 0) ++ goto fail; ++ ++ params.beacon_ies = beacon; ++ params.proberesp_ies = proberesp; ++ params.assocresp_ies = assocresp; ++ params.reenable = hapd->reenable_beacon; ++ hapd->reenable_beacon = 0; ++ ++ if (iface->current_mode && ++ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, ++ iconf->channel, iconf->ieee80211n, ++ iconf->ieee80211ac, ++ iconf->secondary_channel, ++ iconf->vht_oper_chwidth, ++ iconf->vht_oper_centr_freq_seg0_idx, ++ iconf->vht_oper_centr_freq_seg1_idx, ++ iface->current_mode->vht_capab) == 0) ++ params.freq = &freq; ++ ++ res = hostapd_drv_set_ap(hapd, ¶ms); ++ hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); ++ if (res) ++ wpa_printf(MSG_ERROR, "Failed to set beacon parameters"); ++ else ++ ret = 0; ++fail: ++ ieee802_11_free_ap_params(¶ms); ++ return ret; ++} ++ ++ ++int ieee802_11_set_beacons(struct hostapd_iface *iface) ++{ ++ size_t i; ++ int ret = 0; ++ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (iface->bss[i]->started && ++ ieee802_11_set_beacon(iface->bss[i]) < 0) ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/* only update beacons if started */ ++int ieee802_11_update_beacons(struct hostapd_iface *iface) ++{ ++ size_t i; ++ int ret = 0; ++ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (iface->bss[i]->beacon_set_done && iface->bss[i]->started && ++ ieee802_11_set_beacon(iface->bss[i]) < 0) ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++#endif /* CONFIG_NATIVE_WINDOWS */ +diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c +index fc8786d..efd3841 100644 +--- a/src/ap/hw_features.c ++++ b/src/ap/hw_features.c +@@ -494,7 +494,10 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) + iface->num_ht40_scan_tries = 1; + eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); + eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); +- return 1; ++ ++ //DRIVER_RTW Modify ++ //return -1; ++ return 0;//ignore this error + } + + if (ret < 0) { +diff --git a/src/ap/hw_features.c.orig b/src/ap/hw_features.c.orig +new file mode 100644 +index 0000000..fc8786d +--- /dev/null ++++ b/src/ap/hw_features.c.orig +@@ -0,0 +1,980 @@ ++/* ++ * hostapd / Hardware feature query and different modes ++ * Copyright 2002-2003, Instant802 Networks, Inc. ++ * Copyright 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2008-2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++ ++#include "utils/common.h" ++#include "utils/eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/ieee802_11_common.h" ++#include "common/wpa_ctrl.h" ++#include "common/hw_features_common.h" ++#include "hostapd.h" ++#include "ap_config.h" ++#include "ap_drv_ops.h" ++#include "acs.h" ++#include "ieee802_11.h" ++#include "beacon.h" ++#include "hw_features.h" ++ ++ ++void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, ++ size_t num_hw_features) ++{ ++ size_t i; ++ ++ if (hw_features == NULL) ++ return; ++ ++ for (i = 0; i < num_hw_features; i++) { ++ os_free(hw_features[i].channels); ++ os_free(hw_features[i].rates); ++ } ++ ++ os_free(hw_features); ++} ++ ++ ++#ifndef CONFIG_NO_STDOUT_DEBUG ++static char * dfs_info(struct hostapd_channel_data *chan) ++{ ++ static char info[256]; ++ char *state; ++ ++ switch (chan->flag & HOSTAPD_CHAN_DFS_MASK) { ++ case HOSTAPD_CHAN_DFS_UNKNOWN: ++ state = "unknown"; ++ break; ++ case HOSTAPD_CHAN_DFS_USABLE: ++ state = "usable"; ++ break; ++ case HOSTAPD_CHAN_DFS_UNAVAILABLE: ++ state = "unavailable"; ++ break; ++ case HOSTAPD_CHAN_DFS_AVAILABLE: ++ state = "available"; ++ break; ++ default: ++ return ""; ++ } ++ os_snprintf(info, sizeof(info), " (DFS state = %s)", state); ++ info[sizeof(info) - 1] = '\0'; ++ ++ return info; ++} ++#endif /* CONFIG_NO_STDOUT_DEBUG */ ++ ++ ++int hostapd_get_hw_features(struct hostapd_iface *iface) ++{ ++ struct hostapd_data *hapd = iface->bss[0]; ++ int i, j; ++ u16 num_modes, flags; ++ struct hostapd_hw_modes *modes; ++ ++ if (hostapd_drv_none(hapd)) ++ return -1; ++ modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); ++ if (modes == NULL) { ++ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_DEBUG, ++ "Fetching hardware channel/rate support not " ++ "supported."); ++ return -1; ++ } ++ ++ iface->hw_flags = flags; ++ ++ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); ++ iface->hw_features = modes; ++ iface->num_hw_features = num_modes; ++ ++ for (i = 0; i < num_modes; i++) { ++ struct hostapd_hw_modes *feature = &modes[i]; ++ int dfs_enabled = hapd->iconf->ieee80211h && ++ (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); ++ ++ /* set flag for channels we can use in current regulatory ++ * domain */ ++ for (j = 0; j < feature->num_channels; j++) { ++ int dfs = 0; ++ ++ /* ++ * Disable all channels that are marked not to allow ++ * to initiate radiation (a.k.a. passive scan and no ++ * IBSS). ++ * Use radar channels only if the driver supports DFS. ++ */ ++ if ((feature->channels[j].flag & ++ HOSTAPD_CHAN_RADAR) && dfs_enabled) { ++ dfs = 1; ++ } else if (((feature->channels[j].flag & ++ HOSTAPD_CHAN_RADAR) && ++ !(iface->drv_flags & ++ WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || ++ (feature->channels[j].flag & ++ HOSTAPD_CHAN_NO_IR)) { ++ feature->channels[j].flag |= ++ HOSTAPD_CHAN_DISABLED; ++ } ++ ++ if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ ++ wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " ++ "chan=%d freq=%d MHz max_tx_power=%d dBm%s", ++ feature->mode, ++ feature->channels[j].chan, ++ feature->channels[j].freq, ++ feature->channels[j].max_tx_power, ++ dfs ? dfs_info(&feature->channels[j]) : ""); ++ } ++ } ++ ++ return 0; ++} ++ ++ ++int hostapd_prepare_rates(struct hostapd_iface *iface, ++ struct hostapd_hw_modes *mode) ++{ ++ int i, num_basic_rates = 0; ++ int basic_rates_a[] = { 60, 120, 240, -1 }; ++ int basic_rates_b[] = { 10, 20, -1 }; ++ int basic_rates_g[] = { 10, 20, 55, 110, -1 }; ++ int *basic_rates; ++ ++ if (iface->conf->basic_rates) ++ basic_rates = iface->conf->basic_rates; ++ else switch (mode->mode) { ++ case HOSTAPD_MODE_IEEE80211A: ++ basic_rates = basic_rates_a; ++ break; ++ case HOSTAPD_MODE_IEEE80211B: ++ basic_rates = basic_rates_b; ++ break; ++ case HOSTAPD_MODE_IEEE80211G: ++ basic_rates = basic_rates_g; ++ break; ++ case HOSTAPD_MODE_IEEE80211AD: ++ return 0; /* No basic rates for 11ad */ ++ default: ++ return -1; ++ } ++ ++ i = 0; ++ while (basic_rates[i] >= 0) ++ i++; ++ if (i) ++ i++; /* -1 termination */ ++ os_free(iface->basic_rates); ++ iface->basic_rates = os_malloc(i * sizeof(int)); ++ if (iface->basic_rates) ++ os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int)); ++ ++ os_free(iface->current_rates); ++ iface->num_rates = 0; ++ ++ iface->current_rates = ++ os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); ++ if (!iface->current_rates) { ++ wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " ++ "table."); ++ return -1; ++ } ++ ++ for (i = 0; i < mode->num_rates; i++) { ++ struct hostapd_rate_data *rate; ++ ++ if (iface->conf->supported_rates && ++ !hostapd_rate_found(iface->conf->supported_rates, ++ mode->rates[i])) ++ continue; ++ ++ rate = &iface->current_rates[iface->num_rates]; ++ rate->rate = mode->rates[i]; ++ if (hostapd_rate_found(basic_rates, rate->rate)) { ++ rate->flags |= HOSTAPD_RATE_BASIC; ++ num_basic_rates++; ++ } ++ wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", ++ iface->num_rates, rate->rate, rate->flags); ++ iface->num_rates++; ++ } ++ ++ if ((iface->num_rates == 0 || num_basic_rates == 0) && ++ (!iface->conf->ieee80211n || !iface->conf->require_ht)) { ++ wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " ++ "rate sets (%d,%d).", ++ iface->num_rates, num_basic_rates); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_IEEE80211N ++static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) ++{ ++ int pri_chan, sec_chan; ++ ++ if (!iface->conf->secondary_channel) ++ return 1; /* HT40 not used */ ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ return allowed_ht40_channel_pair(iface->current_mode, pri_chan, ++ sec_chan); ++} ++ ++ ++static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) ++{ ++ if (iface->conf->secondary_channel > 0) { ++ iface->conf->channel += 4; ++ iface->conf->secondary_channel = -1; ++ } else { ++ iface->conf->channel -= 4; ++ iface->conf->secondary_channel = 1; ++ } ++} ++ ++ ++static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, ++ struct wpa_scan_results *scan_res) ++{ ++ int pri_chan, sec_chan; ++ int res; ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan); ++ ++ 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; ++} ++ ++ ++static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, ++ struct wpa_scan_results *scan_res) ++{ ++ int pri_chan, sec_chan; ++ ++ pri_chan = iface->conf->channel; ++ sec_chan = pri_chan + iface->conf->secondary_channel * 4; ++ ++ return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan, ++ sec_chan); ++} ++ ++ ++static void ieee80211n_check_scan(struct hostapd_iface *iface) ++{ ++ struct wpa_scan_results *scan_res; ++ int oper40; ++ int res; ++ ++ /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is ++ * allowed per IEEE Std 802.11-2012, 10.15.3.2 */ ++ ++ iface->scan_cb = NULL; ++ ++ scan_res = hostapd_driver_get_scan_results(iface->bss[0]); ++ if (scan_res == NULL) { ++ hostapd_setup_interface_complete(iface, 1); ++ return; ++ } ++ ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) ++ oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); ++ else ++ oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); ++ wpa_scan_results_free(scan_res); ++ ++ iface->secondary_ch = iface->conf->secondary_channel; ++ if (!oper40) { ++ wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " ++ "channel pri=%d sec=%d based on overlapping BSSes", ++ iface->conf->channel, ++ iface->conf->channel + ++ iface->conf->secondary_channel * 4); ++ iface->conf->secondary_channel = 0; ++ if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) { ++ /* ++ * TODO: Could consider scheduling another scan to check ++ * if channel width can be changed if no coex reports ++ * are received from associating stations. ++ */ ++ } ++ } ++ ++ res = ieee80211n_allowed_ht40_channel_pair(iface); ++ if (!res) { ++ iface->conf->secondary_channel = 0; ++ wpa_printf(MSG_INFO, "Fallback to 20 MHz"); ++ } ++ ++ hostapd_setup_interface_complete(iface, !res); ++} ++ ++ ++static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface, ++ struct wpa_driver_scan_params *params) ++{ ++ /* Scan only the affected frequency range */ ++ int pri_freq, sec_freq; ++ int affected_start, affected_end; ++ int i, pos; ++ struct hostapd_hw_modes *mode; ++ ++ if (iface->current_mode == NULL) ++ return; ++ ++ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); ++ if (iface->conf->secondary_channel > 0) ++ sec_freq = pri_freq + 20; ++ else ++ sec_freq = pri_freq - 20; ++ /* ++ * 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); ++ ++ mode = iface->current_mode; ++ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); ++ if (params->freqs == NULL) ++ return; ++ pos = 0; ++ ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (chan->freq < affected_start || ++ chan->freq > affected_end) ++ continue; ++ params->freqs[pos++] = chan->freq; ++ } ++} ++ ++ ++static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface, ++ struct wpa_driver_scan_params *params) ++{ ++ /* Scan only the affected frequency range */ ++ int pri_freq; ++ int affected_start, affected_end; ++ int i, pos; ++ struct hostapd_hw_modes *mode; ++ ++ if (iface->current_mode == NULL) ++ return; ++ ++ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); ++ if (iface->conf->secondary_channel > 0) { ++ affected_start = pri_freq - 10; ++ affected_end = pri_freq + 30; ++ } else { ++ affected_start = pri_freq - 30; ++ affected_end = pri_freq + 10; ++ } ++ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", ++ affected_start, affected_end); ++ ++ mode = iface->current_mode; ++ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int)); ++ if (params->freqs == NULL) ++ return; ++ pos = 0; ++ ++ for (i = 0; i < mode->num_channels; i++) { ++ struct hostapd_channel_data *chan = &mode->channels[i]; ++ if (chan->flag & HOSTAPD_CHAN_DISABLED) ++ continue; ++ if (chan->freq < affected_start || ++ chan->freq > affected_end) ++ continue; ++ params->freqs[pos++] = chan->freq; ++ } ++} ++ ++ ++static void ap_ht40_scan_retry(void *eloop_data, void *user_data) ++{ ++#define HT2040_COEX_SCAN_RETRY 15 ++ struct hostapd_iface *iface = eloop_data; ++ struct wpa_driver_scan_params params; ++ int ret; ++ ++ os_memset(¶ms, 0, sizeof(params)); ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ ieee80211n_scan_channels_2g4(iface, ¶ms); ++ else ++ ieee80211n_scan_channels_5g(iface, ¶ms); ++ ++ ret = hostapd_driver_scan(iface->bss[0], ¶ms); ++ iface->num_ht40_scan_tries++; ++ os_free(params.freqs); ++ ++ if (ret == -EBUSY && ++ iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)", ++ ret, strerror(-ret), iface->num_ht40_scan_tries); ++ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); ++ return; ++ } ++ ++ if (ret == 0) { ++ iface->scan_cb = ieee80211n_check_scan; ++ return; ++ } ++ ++ wpa_printf(MSG_DEBUG, ++ "Failed to request a scan in device, bringing up in HT20 mode"); ++ iface->conf->secondary_channel = 0; ++ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; ++ hostapd_setup_interface_complete(iface, 0); ++} ++ ++ ++void hostapd_stop_setup_timers(struct hostapd_iface *iface) ++{ ++ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); ++} ++ ++ ++static int ieee80211n_check_40mhz(struct hostapd_iface *iface) ++{ ++ struct wpa_driver_scan_params params; ++ int ret; ++ ++ if (!iface->conf->secondary_channel) ++ return 0; /* HT40 not used */ ++ ++ hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); ++ wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " ++ "40 MHz channel"); ++ os_memset(¶ms, 0, sizeof(params)); ++ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) ++ ieee80211n_scan_channels_2g4(iface, ¶ms); ++ else ++ ieee80211n_scan_channels_5g(iface, ¶ms); ++ ++ ret = hostapd_driver_scan(iface->bss[0], ¶ms); ++ os_free(params.freqs); ++ ++ if (ret == -EBUSY) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again", ++ ret, strerror(-ret)); ++ iface->num_ht40_scan_tries = 1; ++ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); ++ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); ++ return 1; ++ } ++ ++ if (ret < 0) { ++ wpa_printf(MSG_ERROR, ++ "Failed to request a scan of neighboring BSSes ret=%d (%s)", ++ ret, strerror(-ret)); ++ return -1; ++ } ++ ++ iface->scan_cb = ieee80211n_check_scan; ++ return 1; ++} ++ ++ ++static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) ++{ ++ u16 hw = iface->current_mode->ht_capab; ++ u16 conf = iface->conf->ht_capab; ++ ++ if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && ++ !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [LDPC]"); ++ return 0; ++ } ++ ++ /* ++ * 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*]"); ++ return 0; ++ } ++ ++ switch (conf & HT_CAP_INFO_SMPS_MASK) { ++ case HT_CAP_INFO_SMPS_STATIC: ++ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) { ++ wpa_printf(MSG_ERROR, ++ "Driver does not support configured HT capability [SMPS-STATIC]"); ++ return 0; ++ } ++ break; ++ case HT_CAP_INFO_SMPS_DYNAMIC: ++ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) { ++ wpa_printf(MSG_ERROR, ++ "Driver does not support configured HT capability [SMPS-DYNAMIC]"); ++ return 0; ++ } ++ break; ++ case HT_CAP_INFO_SMPS_DISABLED: ++ default: ++ break; ++ } ++ ++ if ((conf & HT_CAP_INFO_GREEN_FIELD) && ++ !(hw & HT_CAP_INFO_GREEN_FIELD)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [GF]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && ++ !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [SHORT-GI-20]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && ++ !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [SHORT-GI-40]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [TX-STBC]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_RX_STBC_MASK) > ++ (hw & HT_CAP_INFO_RX_STBC_MASK)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [RX-STBC*]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_DELAYED_BA) && ++ !(hw & HT_CAP_INFO_DELAYED_BA)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [DELAYED-BA]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && ++ !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [MAX-AMSDU-7935]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && ++ !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [DSSS_CCK-40]"); ++ return 0; ++ } ++ ++ if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && ++ !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured " ++ "HT capability [LSIG-TXOP-PROT]"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++#ifdef CONFIG_IEEE80211AC ++ ++static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) ++{ ++ u32 req_cap = conf & cap; ++ ++ /* ++ * Make sure we support all requested capabilities. ++ * NOTE: We assume that 'cap' represents a capability mask, ++ * not a discrete value. ++ */ ++ if ((hw & req_cap) != req_cap) { ++ wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", ++ name); ++ return 0; ++ } ++ return 1; ++} ++ ++ ++static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask, ++ unsigned int shift, ++ const char *name) ++{ ++ u32 hw_max = hw & mask; ++ u32 conf_val = conf & mask; ++ ++ if (conf_val > hw_max) { ++ wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", ++ name, conf_val >> shift, hw_max >> shift); ++ return 0; ++ } ++ return 1; ++} ++ ++ ++static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) ++{ ++ struct hostapd_hw_modes *mode = iface->current_mode; ++ u32 hw = mode->vht_capab; ++ u32 conf = iface->conf->vht_capab; ++ ++ wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x", ++ hw, conf); ++ ++ if (mode->mode == HOSTAPD_MODE_IEEE80211G && ++ iface->conf->bss[0]->vendor_vht && ++ mode->vht_capab == 0 && iface->hw_features) { ++ int i; ++ ++ for (i = 0; i < iface->num_hw_features; i++) { ++ if (iface->hw_features[i].mode == ++ HOSTAPD_MODE_IEEE80211A) { ++ mode = &iface->hw_features[i]; ++ hw = mode->vht_capab; ++ wpa_printf(MSG_DEBUG, ++ "update hw vht capab based on 5 GHz band: 0x%x", ++ hw); ++ break; ++ } ++ } ++ } ++ ++#define VHT_CAP_CHECK(cap) \ ++ do { \ ++ if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ ++ return 0; \ ++ } while (0) ++ ++#define VHT_CAP_CHECK_MAX(cap) \ ++ do { \ ++ if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \ ++ #cap)) \ ++ return 0; \ ++ } while (0) ++ ++ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); ++ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); ++ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); ++ VHT_CAP_CHECK(VHT_CAP_RXLDPC); ++ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); ++ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); ++ VHT_CAP_CHECK(VHT_CAP_TXSTBC); ++ VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); ++ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); ++ VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); ++ VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); ++ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); ++ VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); ++ VHT_CAP_CHECK(VHT_CAP_HTC_VHT); ++ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); ++ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); ++ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); ++ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); ++ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); ++ ++#undef VHT_CAP_CHECK ++#undef VHT_CAP_CHECK_MAX ++ ++ return 1; ++} ++#endif /* CONFIG_IEEE80211AC */ ++ ++#endif /* CONFIG_IEEE80211N */ ++ ++ ++int hostapd_check_ht_capab(struct hostapd_iface *iface) ++{ ++#ifdef CONFIG_IEEE80211N ++ 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 ++ if (!ieee80211ac_supported_vht_capab(iface)) ++ return -1; ++#endif /* CONFIG_IEEE80211AC */ ++ ret = ieee80211n_check_40mhz(iface); ++ if (ret) ++ return ret; ++ if (!ieee80211n_allowed_ht40_channel_pair(iface)) ++ return -1; ++#endif /* CONFIG_IEEE80211N */ ++ ++ return 0; ++} ++ ++ ++static int hostapd_is_usable_chan(struct hostapd_iface *iface, ++ int channel, int primary) ++{ ++ int i; ++ struct hostapd_channel_data *chan; ++ ++ if (!iface->current_mode) ++ return 0; ++ ++ for (i = 0; i < iface->current_mode->num_channels; i++) { ++ chan = &iface->current_mode->channels[i]; ++ if (chan->chan != channel) ++ continue; ++ ++ if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) ++ return 1; ++ ++ wpa_printf(MSG_DEBUG, ++ "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s", ++ primary ? "" : "Configured HT40 secondary ", ++ i, chan->chan, chan->flag, ++ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", ++ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); ++ } ++ ++ return 0; ++} ++ ++ ++static int hostapd_is_usable_chans(struct hostapd_iface *iface) ++{ ++ if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) ++ return 0; ++ ++ if (!iface->conf->secondary_channel) ++ return 1; ++ ++ return hostapd_is_usable_chan(iface, iface->conf->channel + ++ iface->conf->secondary_channel * 4, 0); ++} ++ ++ ++static enum hostapd_chan_status ++hostapd_check_chans(struct hostapd_iface *iface) ++{ ++ if (iface->conf->channel) { ++ if (hostapd_is_usable_chans(iface)) ++ return HOSTAPD_CHAN_VALID; ++ else ++ return HOSTAPD_CHAN_INVALID; ++ } ++ ++ /* ++ * The user set channel=0 or channel=acs_survey ++ * which is used to trigger ACS. ++ */ ++ ++ switch (acs_init(iface)) { ++ case HOSTAPD_CHAN_ACS: ++ return HOSTAPD_CHAN_ACS; ++ case HOSTAPD_CHAN_VALID: ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ return HOSTAPD_CHAN_INVALID; ++ } ++} ++ ++ ++static void hostapd_notify_bad_chans(struct hostapd_iface *iface) ++{ ++ 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, ++ "Configured channel (%d) not found from the " ++ "channel list of current mode (%d) %s", ++ iface->conf->channel, ++ iface->current_mode->mode, ++ hostapd_hw_mode_txt(iface->current_mode->mode)); ++ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, ++ HOSTAPD_LEVEL_WARNING, ++ "Hardware does not support configured channel"); ++} ++ ++ ++int hostapd_acs_completed(struct hostapd_iface *iface, int err) ++{ ++ int ret = -1; ++ ++ if (err) ++ goto out; ++ ++ switch (hostapd_check_chans(iface)) { ++ case HOSTAPD_CHAN_VALID: ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ++ ACS_EVENT_COMPLETED "freq=%d channel=%d", ++ hostapd_hw_get_freq(iface->bss[0], ++ iface->conf->channel), ++ iface->conf->channel); ++ break; ++ case HOSTAPD_CHAN_ACS: ++ wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available"); ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); ++ hostapd_notify_bad_chans(iface); ++ goto out; ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ wpa_printf(MSG_ERROR, "ACS picked unusable channels"); ++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); ++ hostapd_notify_bad_chans(iface); ++ goto out; ++ } ++ ++ ret = hostapd_check_ht_capab(iface); ++ if (ret < 0) ++ goto out; ++ if (ret == 1) { ++ wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback"); ++ return 0; ++ } ++ ++ ret = 0; ++out: ++ return hostapd_setup_interface_complete(iface, ret); ++} ++ ++ ++/** ++ * hostapd_select_hw_mode - Select the hardware mode ++ * @iface: Pointer to interface data. ++ * Returns: 0 on success, < 0 on failure ++ * ++ * Sets up the hardware mode, channel, rates, and passive scanning ++ * based on the configuration. ++ */ ++int hostapd_select_hw_mode(struct hostapd_iface *iface) ++{ ++ int i; ++ ++ if (iface->num_hw_features < 1) ++ return -1; ++ ++ if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || ++ iface->conf->ieee80211n || iface->conf->ieee80211ac) && ++ iface->conf->channel == 14) { ++ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14"); ++ iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; ++ iface->conf->ieee80211n = 0; ++ iface->conf->ieee80211ac = 0; ++ } ++ ++ iface->current_mode = NULL; ++ for (i = 0; i < iface->num_hw_features; i++) { ++ struct hostapd_hw_modes *mode = &iface->hw_features[i]; ++ if (mode->mode == iface->conf->hw_mode) { ++ iface->current_mode = mode; ++ break; ++ } ++ } ++ ++ if (iface->current_mode == NULL) { ++ 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)) { ++ case HOSTAPD_CHAN_VALID: ++ return 0; ++ case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ ++ return 1; ++ case HOSTAPD_CHAN_INVALID: ++ default: ++ hostapd_notify_bad_chans(iface); ++ return -3; ++ } ++} ++ ++ ++const char * hostapd_hw_mode_txt(int mode) ++{ ++ switch (mode) { ++ case HOSTAPD_MODE_IEEE80211A: ++ return "IEEE 802.11a"; ++ case HOSTAPD_MODE_IEEE80211B: ++ return "IEEE 802.11b"; ++ case HOSTAPD_MODE_IEEE80211G: ++ return "IEEE 802.11g"; ++ case HOSTAPD_MODE_IEEE80211AD: ++ return "IEEE 802.11ad"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++ ++int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) ++{ ++ return hw_get_freq(hapd->iface->current_mode, chan); ++} ++ ++ ++int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) ++{ ++ return hw_get_chan(hapd->iface->current_mode, freq); ++} +diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c +index bab1f03..555d0d8 100644 +--- a/src/drivers/driver_bsd.c ++++ b/src/drivers/driver_bsd.c +@@ -47,6 +47,12 @@ + + #include "l2_packet/l2_packet.h" + ++#ifdef HOSTAPD ++#ifdef CONFIG_SUPPORT_RTW_DRIVER ++#define RTW_BSD_HOSTAPD_SET_BEACON (1100) ++#endif ++#endif ++ + struct bsd_driver_data { + struct hostapd_data *hapd; /* back pointer */ + +@@ -800,6 +806,296 @@ handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) + drv_event_eapol_rx(drv->hapd, src_addr, buf, len); + } + ++#ifdef CONFIG_SUPPORT_RTW_DRIVER ++static int rtw_set_beacon_ops(void *priv, const u8 *head, size_t head_len, ++ const u8 *tail, size_t tail_len, int dtim_period, ++ int beacon_int) ++{ ++ int ret=0; ++ u8 *pbuf; ++ size_t sz; ++ struct bsd_driver_data *drv = priv; ++ ++ if((head_len<24) ||(!head)) ++ return -1; ++ ++ sz = head_len+tail_len - 24; // 24 = wlan hdr ++ ++ printf("%s, beacon_sz=%d\n", __func__, sz); ++ ++ pbuf = os_zalloc(sz); ++ if (pbuf == NULL) { ++ return -ENOMEM; ++ } ++ ++ os_memcpy(pbuf, (head+24), (head_len-24));// 24=beacon header len. ++ ++ os_memcpy(&pbuf[head_len-24], tail, tail_len); ++ ++ ret = set80211var(drv, RTW_BSD_HOSTAPD_SET_BEACON, pbuf, sz); ++ ++ os_free(pbuf); ++ ++ return ret; ++ ++} ++ ++static struct hostapd_hw_modes *rtw_get_hw_feature_data_ops( ++ void *priv, u16 *num_modes, u16 *flags) ++{ ++ ++#define MAX_NUM_CHANNEL (14) ++#define MAX_NUM_CHANNEL_5G (24) ++ ++ struct hostapd_hw_modes *modes; ++ size_t i; ++ int k; ++ ++ printf("%s\n", __func__); ++ ++ *num_modes = 3; ++ *flags = 0; ++ ++ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); ++ if (modes == NULL) ++ return NULL; ++ ++ //.1 ++ modes[0].mode = HOSTAPD_MODE_IEEE80211G; ++ modes[0].num_channels = MAX_NUM_CHANNEL; ++ modes[0].num_rates = 12; ++ modes[0].channels = ++ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); ++ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); ++ if (modes[0].channels == NULL || modes[0].rates == NULL) ++ goto fail; ++ for (i = 0; i < MAX_NUM_CHANNEL; i++) { ++ modes[0].channels[i].chan = i + 1; ++ modes[0].channels[i].freq = 2412 + 5 * i; ++ modes[0].channels[i].flag = 0; ++ if (i >= 13) ++ modes[0].channels[i].flag = HOSTAPD_CHAN_DISABLED; ++ } ++ modes[0].rates[0] = 10; ++ modes[0].rates[1] = 20; ++ modes[0].rates[2] = 55; ++ modes[0].rates[3] = 110; ++ modes[0].rates[4] = 60; ++ modes[0].rates[5] = 90; ++ modes[0].rates[6] = 120; ++ modes[0].rates[7] = 180; ++ modes[0].rates[8] = 240; ++ modes[0].rates[9] = 360; ++ modes[0].rates[10] = 480; ++ modes[0].rates[11] = 540; ++ ++ ++ //.2 ++ modes[1].mode = HOSTAPD_MODE_IEEE80211B; ++ modes[1].num_channels = MAX_NUM_CHANNEL; ++ modes[1].num_rates = 4; ++ modes[1].channels = ++ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); ++ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); ++ if (modes[1].channels == NULL || modes[1].rates == NULL) ++ goto fail; ++ for (i = 0; i < MAX_NUM_CHANNEL; i++) { ++ modes[1].channels[i].chan = i + 1; ++ modes[1].channels[i].freq = 2412 + 5 * i; ++ modes[1].channels[i].flag = 0; ++ if (i >= 11) ++ modes[1].channels[i].flag = HOSTAPD_CHAN_DISABLED; ++ } ++ modes[1].rates[0] = 10; ++ modes[1].rates[1] = 20; ++ modes[1].rates[2] = 55; ++ modes[1].rates[3] = 110; ++ ++ ++ //.3 ++ modes[2].mode = HOSTAPD_MODE_IEEE80211A; ++#ifdef CONFIG_DRIVER_RTL_DFS ++ modes[2].num_channels = MAX_NUM_CHANNEL_5G; ++#else /* CONFIG_DRIVER_RTL_DFS */ ++ modes[2].num_channels = 9; ++#endif /* CONFIG_DRIVER_RTL_DFS */ ++ ++ modes[2].num_rates = 8; ++ modes[2].channels = os_zalloc(modes[2].num_channels * sizeof(struct hostapd_channel_data)); ++ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); ++ if (modes[2].channels == NULL || modes[2].rates == NULL) ++ goto fail; ++ ++ ++ k = 0; ++ // 5G band1 Channel: 36, 40, 44, 48 ++ for (i=0; i < 4; i++) { ++ modes[2].channels[k].chan = 36+(i*4); ++ modes[2].channels[k].freq = 5180+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++#ifdef CONFIG_DRIVER_RTL_DFS ++ // 5G band2 Channel: 52, 56, 60, 64 ++ for (i=0; i < 4; i++) { ++ modes[2].channels[k].chan = 52+(i*4); ++ modes[2].channels[k].freq = 5260+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++ // 5G band3 Channel: 100, 104, 108. 112, 116, 120, 124, 128, 132, 136, 140 ++ for (i=0; i < 11; i++) { ++ modes[2].channels[k].chan = 100+(i*4); ++ modes[2].channels[k].freq = 5500+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++#endif /* CONFIG_DRIVER_RTL_DFS */ ++ ++ // 5G band4 Channel: 149, 153, 157, 161, 165 ++ for (i=0; i < 5; i++) { ++ modes[2].channels[k].chan = 149+(i*4); ++ modes[2].channels[k].freq = 5745+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++ modes[2].rates[0] = 60; ++ modes[2].rates[1] = 90; ++ modes[2].rates[2] = 120; ++ modes[2].rates[3] = 180; ++ modes[2].rates[4] = 240; ++ modes[2].rates[5] = 360; ++ modes[2].rates[6] = 480; ++ modes[2].rates[7] = 540; ++ ++ ++ // ++#if 0 ++#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) ++#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) ++#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) ++#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) ++#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) ++#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) ++#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) ++#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) ++#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) ++#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) ++#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) ++#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) ++#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) ++#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) ++#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) ++#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) ++#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) ++#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) ++#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) ++#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) ++#endif ++ ++ //HOSTAPD_MODE_IEEE80211G ++ modes[0].ht_capab = HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET|HT_CAP_INFO_SHORT_GI20MHZ| ++ HT_CAP_INFO_SHORT_GI40MHZ|HT_CAP_INFO_MAX_AMSDU_SIZE|HT_CAP_INFO_DSSS_CCK40MHZ; ++ ++ modes[0].mcs_set[0]= 0xff; ++ modes[0].mcs_set[1]= 0xff; ++ ++ //HOSTAPD_MODE_IEEE80211B ++ modes[1].ht_capab = 0; ++ ++ //HOSTAPD_MODE_IEEE80211A ++ modes[2].ht_capab = modes[0].ht_capab; ++ ++ modes[2].mcs_set[0]= 0xff; ++ modes[2].mcs_set[1]= 0xff; ++ ++ return modes; ++ ++fail: ++ if (modes) { ++ for (i = 0; i < *num_modes; i++) { ++ os_free(modes[i].channels); ++ os_free(modes[i].rates); ++ } ++ os_free(modes); ++ } ++ ++ return NULL; ++ ++} ++ ++#if 0 ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_SHIFT 2 ++#define IEEE80211_FC0_TYPE_MGT 0x00 ++#define IEEE80211_FC0_TYPE_CTL 0x04 ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 ++#define IEEE80211_FC0_SUBTYPE_SHIFT 4 ++#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 ++#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 ++#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 ++#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 ++#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 ++#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 ++#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 ++#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 ++#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 ++#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 ++#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 ++#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 ++#define IEEE80211_FC0_SUBTYPE_ACTION_NOACK 0xe0 ++ ++#define IEEE80211_APPIE_WPA (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON | \ ++ IEEE80211_FC0_SUBTYPE_PROBE_RESP) ++ ++#endif ++ ++#define RTW_IEEE80211_APPIE_BEACON (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_BEACON) ++#define RTW_IEEE80211_APPIE_PROBE_RESP (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_PROBE_RESP) ++#define RTW_IEEE80211_APPIE_ASSOC_RESP (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_ASSOC_RESP) ++ ++ ++static int rtw_set_wps_assoc_resp_ie(void *priv, const void *ie, size_t len) ++{ ++ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_ASSOC_RESP, ++ ie, len); ++} ++ ++static int rtw_set_wps_beacon_ie(void *priv, const void *ie, size_t len) ++{ ++ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_BEACON, ++ ie, len); ++} ++ ++static int rtw_set_wps_probe_resp_ie(void *priv, const void *ie, size_t len) ++{ ++ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_PROBE_RESP, ++ ie, len); ++} ++ ++static int rtw_set_ap_wps_ie_ops(void *priv, const struct wpabuf *beacon, ++ const struct wpabuf *proberesp, const struct wpabuf *assocresp) ++{ ++ if (rtw_set_wps_assoc_resp_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, ++ assocresp ? wpabuf_len(assocresp) : 0)) ++ return -1; ++ ++ if (rtw_set_wps_beacon_ie(priv, beacon ? wpabuf_head(beacon) : NULL, ++ beacon ? wpabuf_len(beacon) : 0)) ++ return -1; ++ ++ return rtw_set_wps_probe_resp_ie(priv, ++ proberesp ? wpabuf_head(proberesp) : NULL, ++ proberesp ? wpabuf_len(proberesp): 0); ++ ++} ++#endif ++ ++ + static void * + bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) + { +@@ -854,6 +1150,12 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) + goto bad; + } + ++#ifdef CONFIG_SUPPORT_RTW_DRIVER ++ /* mark up after init */ ++ if (bsd_ctrl_iface(drv, 1) < 0) ++ goto bad; ++#endif ++ + return drv; + bad: + if (drv->sock_xmit != NULL) +@@ -1292,6 +1594,15 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) + event.interface_status.ifname); + wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); + } ++ else{ ++ os_strlcpy(event.interface_status.ifname, drv->ifname, ++ sizeof(event.interface_status.ifname)); ++ event.interface_status.ievent = EVENT_INTERFACE_ADDED; ++ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", ++ event.interface_status.ifname); ++ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); ++ } ++ + break; + } + } +@@ -1609,7 +1920,52 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) + } + #endif /* HOSTAPD */ + +- ++#ifdef CONFIG_SUPPORT_RTW_DRIVER ++const struct wpa_driver_ops wpa_driver_bsd_ops = { ++ .name = "bsd", ++ .desc = "BSD 802.11 support", ++#ifdef HOSTAPD ++ .hapd_init = bsd_init, ++ .hapd_deinit = bsd_deinit, ++ .set_privacy = bsd_set_privacy,//del ? ++ .get_seqnum = bsd_get_seqnum,//del ? ++ .flush = bsd_flush, ++ .read_sta_data = bsd_read_sta_driver_data,//del ? ++ .sta_disassoc = bsd_sta_disassoc, ++ .sta_deauth = bsd_sta_deauth, ++ .get_hw_feature_data = rtw_get_hw_feature_data_ops,//add ++ //.sta_remove = rtl871x_sta_remove_ops,//add ++ .set_beacon = rtw_set_beacon_ops, //add ++ .set_ap_wps_ie = rtw_set_ap_wps_ie_ops,//add ++#else /* HOSTAPD */ ++ .init = wpa_driver_bsd_init, ++ .deinit = wpa_driver_bsd_deinit, ++ .get_bssid = wpa_driver_bsd_get_bssid, ++ .get_ssid = wpa_driver_bsd_get_ssid, ++ .set_countermeasures = wpa_driver_bsd_set_countermeasures, ++ .scan2 = wpa_driver_bsd_scan, ++ .get_scan_results2 = wpa_driver_bsd_get_scan_results2, ++ .deauthenticate = wpa_driver_bsd_deauthenticate, ++ .disassociate = wpa_driver_bsd_disassociate, ++ .associate = wpa_driver_bsd_associate, ++ .get_capa = wpa_driver_bsd_get_capa, ++ .set_freq = bsd_set_freq, //only for wpa_supplicant ++ .set_ieee8021x = bsd_set_ieee8021x,//only for wpa_supplicant ++ .hapd_set_ssid = bsd_set_ssid,//only for wpa_supplicant ++ .hapd_get_ssid = bsd_get_ssid,//only for wpa_supplicant ++ .sta_set_flags = bsd_set_sta_authorized, //only for wpa_supplicant ++ .set_generic_elem = bsd_set_opt_ie, //only for wpa_supplicant ++#endif /* HOSTAPD */ ++ //.set_freq = bsd_set_freq, //only for wpa_supplicant ++ .set_key = bsd_set_key, ++ //.set_ieee8021x = bsd_set_ieee8021x, //only for wpa_supplicant ++ //.hapd_set_ssid = bsd_set_ssid, //only for wpa_supplicant ++ //.hapd_get_ssid = bsd_get_ssid, //only for wpa_supplicant ++ .hapd_send_eapol = bsd_send_eapol, //only for wpa_supplicant ++ //.sta_set_flags = bsd_set_sta_authorized, //only for wpa_supplicant ++ //.set_generic_elem = bsd_set_opt_ie, //only for wpa_supplicant ++}; ++#else + const struct wpa_driver_ops wpa_driver_bsd_ops = { + .name = "bsd", + .desc = "BSD 802.11 support", +@@ -1644,3 +2000,4 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { + .hapd_send_eapol = bsd_send_eapol, + .set_generic_elem = bsd_set_opt_ie, + }; ++#endif +diff --git a/src/drivers/driver_bsd.c.orig b/src/drivers/driver_bsd.c.orig +new file mode 100644 +index 0000000..bab1f03 +--- /dev/null ++++ b/src/drivers/driver_bsd.c.orig +@@ -0,0 +1,1646 @@ ++/* ++ * WPA Supplicant - driver interaction with BSD net80211 layer ++ * Copyright (c) 2004, Sam Leffler ++ * Copyright (c) 2004, 2Wire, Inc ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++#include ++#include ++ ++#include "common.h" ++#include "driver.h" ++#include "eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/wpa_common.h" ++ ++#include ++#include ++ ++#ifdef __NetBSD__ ++#include ++#else ++#include ++#endif ++#include ++ ++#ifdef __DragonFly__ ++#include ++#include ++#else /* __DragonFly__ */ ++#ifdef __GLIBC__ ++#include ++#endif /* __GLIBC__ */ ++#include ++#include ++#include ++#endif /* __DragonFly__ || __GLIBC__ */ ++#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ++#include ++#endif ++#if __NetBSD__ ++#include ++#endif ++ ++#include "l2_packet/l2_packet.h" ++ ++struct bsd_driver_data { ++ struct hostapd_data *hapd; /* back pointer */ ++ ++ int sock; /* open socket for 802.11 ioctls */ ++ struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ ++ int route; /* routing socket for events */ ++ char ifname[IFNAMSIZ+1]; /* interface name */ ++ unsigned int ifindex; /* interface index */ ++ void *ctx; ++ struct wpa_driver_capa capa; /* driver capability */ ++ int is_ap; /* Access point mode */ ++ int prev_roaming; /* roaming state to restore on deinit */ ++ int prev_privacy; /* privacy state to restore on deinit */ ++ int prev_wpa; /* wpa state to restore on deinit */ ++ enum ieee80211_opmode opmode; /* operation mode */ ++ char *event_buf; ++ size_t event_buf_len; ++}; ++ ++/* Generic functions for hostapd and wpa_supplicant */ ++ ++static int ++bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ieee80211req ireq; ++ ++ os_memset(&ireq, 0, sizeof(ireq)); ++ os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); ++ ireq.i_type = op; ++ ireq.i_val = val; ++ ireq.i_data = (void *) arg; ++ ireq.i_len = arg_len; ++ ++ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " ++ "arg_len=%u]: %s", op, val, arg_len, ++ strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, ++ int arg_len) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ os_memset(ireq, 0, sizeof(*ireq)); ++ os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); ++ ireq->i_type = op; ++ ireq->i_len = arg_len; ++ ireq->i_data = arg; ++ ++ if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " ++ "arg_len=%u]: %s", op, arg_len, strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) ++{ ++ struct ieee80211req ireq; ++ ++ if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) ++ return -1; ++ return ireq.i_len; ++} ++ ++static int ++set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) ++{ ++ return bsd_set80211(drv, op, 0, arg, arg_len); ++} ++ ++static int ++set80211param(struct bsd_driver_data *drv, int op, int arg) ++{ ++ return bsd_set80211(drv, op, arg, NULL, 0); ++} ++ ++static int ++bsd_get_ssid(void *priv, u8 *ssid, int len) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCG80211NWID ++ struct ieee80211_nwid nwid; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_data = (void *)&nwid; ++ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || ++ nwid.i_len > IEEE80211_NWID_LEN) ++ return -1; ++ os_memcpy(ssid, nwid.i_nwid, nwid.i_len); ++ return nwid.i_len; ++#else ++ return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); ++#endif ++} ++ ++static int ++bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCS80211NWID ++ struct ieee80211_nwid nwid; ++ struct ifreq ifr; ++ ++ os_memcpy(nwid.i_nwid, ssid, ssid_len); ++ nwid.i_len = ssid_len; ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_data = (void *)&nwid; ++ return ioctl(drv->sock, SIOCS80211NWID, &ifr); ++#else ++ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); ++#endif ++} ++ ++static int ++bsd_get_if_media(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifmediareq ifmr; ++ ++ os_memset(&ifmr, 0, sizeof(ifmr)); ++ os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { ++ wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ return ifmr.ifm_current; ++} ++ ++static int ++bsd_set_if_media(void *priv, int media) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ifr.ifr_media = media; ++ ++ if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) ++{ ++ int media = bsd_get_if_media(priv); ++ ++ if (media < 0) ++ return -1; ++ media &= ~mask; ++ media |= mode; ++ if (bsd_set_if_media(priv, media) < 0) ++ return -1; ++ return 0; ++} ++ ++static int ++bsd_del_key(void *priv, const u8 *addr, int key_idx) ++{ ++ struct ieee80211req_del_key wk; ++ ++ os_memset(&wk, 0, sizeof(wk)); ++ if (addr == NULL) { ++ wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); ++ wk.idk_keyix = key_idx; ++ } else { ++ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, ++ MAC2STR(addr)); ++ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); ++ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ ++ } ++ ++ return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); ++} ++ ++static int ++bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) ++{ ++ struct ieee80211req_mlme mlme; ++ ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.im_op = op; ++ mlme.im_reason = reason; ++ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); ++ return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); ++} ++ ++static int ++bsd_ctrl_iface(void *priv, int enable) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ifreq ifr; ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (enable) { ++ if (ifr.ifr_flags & IFF_UP) ++ return 0; ++ ifr.ifr_flags |= IFF_UP; ++ } else { ++ if (!(ifr.ifr_flags & IFF_UP)) ++ return 0; ++ ifr.ifr_flags &= ~IFF_UP; ++ } ++ ++ if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, ++ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, ++ size_t seq_len, const u8 *key, size_t key_len) ++{ ++ struct ieee80211req_key wk; ++#ifdef IEEE80211_KEY_NOREPLAY ++ struct bsd_driver_data *drv = priv; ++#endif /* IEEE80211_KEY_NOREPLAY */ ++ ++ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " ++ "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, ++ set_tx, seq_len, key_len); ++ ++ if (alg == WPA_ALG_NONE) { ++#ifndef HOSTAPD ++ if (addr == NULL || is_broadcast_ether_addr(addr)) ++ return bsd_del_key(priv, NULL, key_idx); ++ else ++#endif /* HOSTAPD */ ++ return bsd_del_key(priv, addr, key_idx); ++ } ++ ++ os_memset(&wk, 0, sizeof(wk)); ++ switch (alg) { ++ case WPA_ALG_WEP: ++ wk.ik_type = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_ALG_TKIP: ++ wk.ik_type = IEEE80211_CIPHER_TKIP; ++ break; ++ case WPA_ALG_CCMP: ++ wk.ik_type = IEEE80211_CIPHER_AES_CCM; ++ break; ++ default: ++ wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); ++ return -1; ++ } ++ ++ wk.ik_flags = IEEE80211_KEY_RECV; ++ if (set_tx) ++ wk.ik_flags |= IEEE80211_KEY_XMIT; ++ ++ if (addr == NULL) { ++ os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); ++ wk.ik_keyix = key_idx; ++ } else { ++ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); ++ /* ++ * Deduce whether group/global or unicast key by checking ++ * the address (yech). Note also that we can only mark global ++ * keys default; doing this for a unicast key is an error. ++ */ ++ if (is_broadcast_ether_addr(addr)) { ++ wk.ik_flags |= IEEE80211_KEY_GROUP; ++ wk.ik_keyix = key_idx; ++ } else { ++ wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : ++ key_idx; ++ } ++ } ++ if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) ++ wk.ik_flags |= IEEE80211_KEY_DEFAULT; ++#ifndef HOSTAPD ++#ifdef IEEE80211_KEY_NOREPLAY ++ /* ++ * Ignore replay failures in IBSS and AHDEMO mode. ++ */ ++ if (drv->opmode == IEEE80211_M_IBSS || ++ drv->opmode == IEEE80211_M_AHDEMO) ++ wk.ik_flags |= IEEE80211_KEY_NOREPLAY; ++#endif /* IEEE80211_KEY_NOREPLAY */ ++#endif /* HOSTAPD */ ++ wk.ik_keylen = key_len; ++ if (seq) { ++#ifdef WORDS_BIGENDIAN ++ /* ++ * wk.ik_keyrsc is in host byte order (big endian), need to ++ * swap it to match with the byte order used in WPA. ++ */ ++ int i; ++ u8 *keyrsc = (u8 *) &wk.ik_keyrsc; ++ for (i = 0; i < seq_len; i++) ++ keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i]; ++#else /* WORDS_BIGENDIAN */ ++ os_memcpy(&wk.ik_keyrsc, seq, seq_len); ++#endif /* WORDS_BIGENDIAN */ ++ } ++ os_memcpy(wk.ik_keydata, key, key_len); ++ ++ return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); ++} ++ ++static int ++bsd_configure_wpa(void *priv, struct wpa_bss_params *params) ++{ ++#ifndef IEEE80211_IOC_APPIE ++ static const char *ciphernames[] = ++ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; ++ int v; ++ ++ switch (params->wpa_group) { ++ case WPA_CIPHER_CCMP: ++ v = IEEE80211_CIPHER_AES_CCM; ++ break; ++ case WPA_CIPHER_TKIP: ++ v = IEEE80211_CIPHER_TKIP; ++ break; ++ case WPA_CIPHER_WEP104: ++ v = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_CIPHER_WEP40: ++ v = IEEE80211_CIPHER_WEP; ++ break; ++ case WPA_CIPHER_NONE: ++ v = IEEE80211_CIPHER_NONE; ++ break; ++ default: ++ wpa_printf(MSG_INFO, "Unknown group key cipher %u", ++ params->wpa_group); ++ return -1; ++ } ++ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", ++ __func__, ciphernames[v], v); ++ if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set group key cipher to %u (%s)", ++ v, ciphernames[v]); ++ return -1; ++ } ++ if (v == IEEE80211_CIPHER_WEP) { ++ /* key length is done only for specific ciphers */ ++ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); ++ if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set group key length to %u", v); ++ return -1; ++ } ++ } ++ ++ v = 0; ++ if (params->wpa_pairwise & WPA_CIPHER_CCMP) ++ v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) ++ v |= 1<wpa_pairwise & WPA_CIPHER_NONE) ++ v |= 1<wpa_key_mgmt); ++ if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, ++ params->wpa_key_mgmt)) { ++ wpa_printf(MSG_INFO, ++ "Unable to set key management algorithms to 0x%x", ++ params->wpa_key_mgmt); ++ return -1; ++ } ++ ++ v = 0; ++ if (params->rsn_preauth) ++ v |= BIT(0); ++ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", ++ __func__, params->rsn_preauth); ++ if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { ++ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", ++ v); ++ return -1; ++ } ++#endif /* IEEE80211_IOC_APPIE */ ++ ++ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); ++ if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { ++ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); ++ ++ if (!params->enabled) { ++ /* XXX restore state */ ++ return set80211param(priv, IEEE80211_IOC_AUTHMODE, ++ IEEE80211_AUTH_AUTO); ++ } ++ if (!params->wpa && !params->ieee802_1x) { ++ wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", ++ __func__); ++ return -1; ++ } ++ if (params->wpa && bsd_configure_wpa(priv, params) != 0) { ++ wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", ++ __func__); ++ return -1; ++ } ++ if (set80211param(priv, IEEE80211_IOC_AUTHMODE, ++ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { ++ wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", ++ __func__); ++ return -1; ++ } ++ return bsd_ctrl_iface(priv, 1); ++} ++ ++static void ++bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) ++{ ++ struct ieee80211req_wpaie ie; ++ int ielen = 0; ++ u8 *iebuf = NULL; ++ ++ /* ++ * Fetch and validate any negotiated WPA/RSN parameters. ++ */ ++ memset(&ie, 0, sizeof(ie)); ++ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); ++ if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { ++ wpa_printf(MSG_INFO, ++ "Failed to get WPA/RSN information element"); ++ goto no_ie; ++ } ++ iebuf = ie.wpa_ie; ++ ielen = ie.wpa_ie[1]; ++ if (ielen == 0) ++ iebuf = NULL; ++ else ++ ielen += 2; ++ ++no_ie: ++ drv_event_assoc(ctx, addr, iebuf, ielen, 0); ++} ++ ++static int ++bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, ++ int encrypt, const u8 *own_addr, u32 flags) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); ++ ++ return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, ++ data_len); ++} ++ ++static int ++bsd_set_freq(void *priv, struct hostapd_freq_params *freq) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCS80211CHANNEL ++ struct ieee80211chanreq creq; ++#endif /* SIOCS80211CHANNEL */ ++ u32 mode; ++ int channel = freq->channel; ++ ++ if (channel < 14) { ++ mode = ++#ifdef CONFIG_IEEE80211N ++ freq->ht_enabled ? IFM_IEEE80211_11NG : ++#endif /* CONFIG_IEEE80211N */ ++ IFM_IEEE80211_11G; ++ } else if (channel == 14) { ++ mode = IFM_IEEE80211_11B; ++ } else { ++ mode = ++#ifdef CONFIG_IEEE80211N ++ freq->ht_enabled ? IFM_IEEE80211_11NA : ++#endif /* CONFIG_IEEE80211N */ ++ IFM_IEEE80211_11A; ++ } ++ if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", ++ __func__); ++ return -1; ++ } ++ ++#ifdef SIOCS80211CHANNEL ++ os_memset(&creq, 0, sizeof(creq)); ++ os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); ++ creq.i_channel = (u_int16_t)channel; ++ return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); ++#else /* SIOCS80211CHANNEL */ ++ return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); ++#endif /* SIOCS80211CHANNEL */ ++} ++ ++static int ++bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) ++{ ++#ifdef IEEE80211_IOC_APPIE ++ wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, ++ (unsigned long)ie_len); ++ return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, ++ ie, ie_len); ++#endif /* IEEE80211_IOC_APPIE */ ++ return 0; ++} ++ ++static size_t ++rtbuf_len(void) ++{ ++ size_t len; ++ ++ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; ++ ++ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { ++ wpa_printf(MSG_WARNING, "%s failed: %s", __func__, ++ strerror(errno)); ++ len = 2048; ++ } ++ ++ return len; ++} ++ ++#ifdef HOSTAPD ++ ++/* ++ * Avoid conflicts with hostapd definitions by undefining couple of defines ++ * from net80211 header files. ++ */ ++#undef RSN_VERSION ++#undef WPA_VERSION ++#undef WPA_OUI_TYPE ++ ++static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason_code); ++ ++static const char * ++ether_sprintf(const u8 *addr) ++{ ++ static char buf[sizeof(MACSTR)]; ++ ++ if (addr != NULL) ++ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); ++ else ++ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); ++ return buf; ++} ++ ++static int ++bsd_set_privacy(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ ++ return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); ++} ++ ++static int ++bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, ++ u8 *seq) ++{ ++ struct ieee80211req_key wk; ++ ++ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", ++ __func__, ether_sprintf(addr), idx); ++ ++ memset(&wk, 0, sizeof(wk)); ++ if (addr == NULL) ++ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); ++ else ++ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); ++ wk.ik_keyix = idx; ++ ++ if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { ++ wpa_printf(MSG_INFO, "Failed to get encryption"); ++ return -1; ++ } ++ ++#ifdef WORDS_BIGENDIAN ++ { ++ /* ++ * wk.ik_keytsc is in host byte order (big endian), need to ++ * swap it to match with the byte order used in WPA. ++ */ ++ int i; ++ u8 tmp[WPA_KEY_RSC_LEN]; ++ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); ++ for (i = 0; i < WPA_KEY_RSC_LEN; i++) { ++ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; ++ } ++ } ++#else /* WORDS_BIGENDIAN */ ++ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); ++#endif /* WORDS_BIGENDIAN */ ++ return 0; ++} ++ ++ ++static int ++bsd_flush(void *priv) ++{ ++ u8 allsta[IEEE80211_ADDR_LEN]; ++ ++ memset(allsta, 0xff, IEEE80211_ADDR_LEN); ++ return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); ++} ++ ++ ++static int ++bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, ++ const u8 *addr) ++{ ++ struct ieee80211req_sta_stats stats; ++ ++ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); ++ if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) ++ > 0) { ++ /* XXX? do packets counts include non-data frames? */ ++ data->rx_packets = stats.is_stats.ns_rx_data; ++ data->rx_bytes = stats.is_stats.ns_rx_bytes; ++ data->tx_packets = stats.is_stats.ns_tx_data; ++ data->tx_bytes = stats.is_stats.ns_tx_bytes; ++ } ++ return 0; ++} ++ ++static int ++bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, ++ addr); ++} ++ ++static int ++bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, ++ addr); ++} ++ ++static void ++bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) ++{ ++ struct bsd_driver_data *drv = ctx; ++ struct if_announcemsghdr *ifan; ++ struct rt_msghdr *rtm; ++ struct ieee80211_michael_event *mic; ++ struct ieee80211_join_event *join; ++ struct ieee80211_leave_event *leave; ++ int n; ++ union wpa_event_data data; ++ ++ n = read(sock, drv->event_buf, drv->event_buf_len); ++ if (n < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ wpa_printf(MSG_ERROR, "%s read() failed: %s", ++ __func__, strerror(errno)); ++ return; ++ } ++ ++ rtm = (struct rt_msghdr *) drv->event_buf; ++ if (rtm->rtm_version != RTM_VERSION) { ++ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", ++ rtm->rtm_version); ++ return; ++ } ++ ifan = (struct if_announcemsghdr *) rtm; ++ switch (rtm->rtm_type) { ++ case RTM_IEEE80211: ++ switch (ifan->ifan_what) { ++ case RTM_IEEE80211_ASSOC: ++ case RTM_IEEE80211_REASSOC: ++ case RTM_IEEE80211_DISASSOC: ++ case RTM_IEEE80211_SCAN: ++ break; ++ case RTM_IEEE80211_LEAVE: ++ leave = (struct ieee80211_leave_event *) &ifan[1]; ++ drv_event_disassoc(drv->hapd, leave->iev_addr); ++ break; ++ case RTM_IEEE80211_JOIN: ++#ifdef RTM_IEEE80211_REJOIN ++ case RTM_IEEE80211_REJOIN: ++#endif ++ join = (struct ieee80211_join_event *) &ifan[1]; ++ bsd_new_sta(drv, drv->hapd, join->iev_addr); ++ break; ++ case RTM_IEEE80211_REPLAY: ++ /* ignore */ ++ break; ++ case RTM_IEEE80211_MICHAEL: ++ mic = (struct ieee80211_michael_event *) &ifan[1]; ++ wpa_printf(MSG_DEBUG, ++ "Michael MIC failure wireless event: " ++ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, ++ MAC2STR(mic->iev_src)); ++ os_memset(&data, 0, sizeof(data)); ++ data.michael_mic_failure.unicast = 1; ++ data.michael_mic_failure.src = mic->iev_src; ++ wpa_supplicant_event(drv->hapd, ++ EVENT_MICHAEL_MIC_FAILURE, &data); ++ break; ++ } ++ break; ++ } ++} ++ ++static void ++handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct bsd_driver_data *drv = ctx; ++ drv_event_eapol_rx(drv->hapd, src_addr, buf, len); ++} ++ ++static void * ++bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) ++{ ++ struct bsd_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(struct bsd_driver_data)); ++ if (drv == NULL) { ++ wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data"); ++ return NULL; ++ } ++ ++ drv->event_buf_len = rtbuf_len(); ++ ++ drv->event_buf = os_malloc(drv->event_buf_len); ++ if (drv->event_buf == NULL) { ++ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); ++ goto bad; ++ } ++ ++ drv->hapd = hapd; ++ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->sock < 0) { ++ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", ++ strerror(errno)); ++ goto bad; ++ } ++ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); ++ ++ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, ++ handle_read, drv, 0); ++ if (drv->sock_xmit == NULL) ++ goto bad; ++ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) ++ goto bad; ++ ++ /* mark down during setup */ ++ if (bsd_ctrl_iface(drv, 0) < 0) ++ goto bad; ++ ++ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (drv->route < 0) { ++ wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s", ++ strerror(errno)); ++ goto bad; ++ } ++ eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, ++ NULL); ++ ++ if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ goto bad; ++ } ++ ++ return drv; ++bad: ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ if (drv->sock >= 0) ++ close(drv->sock); ++ os_free(drv->event_buf); ++ os_free(drv); ++ return NULL; ++} ++ ++ ++static void ++bsd_deinit(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ if (drv->route >= 0) { ++ eloop_unregister_read_sock(drv->route); ++ close(drv->route); ++ } ++ bsd_ctrl_iface(drv, 0); ++ if (drv->sock >= 0) ++ close(drv->sock); ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ os_free(drv->event_buf); ++ os_free(drv); ++} ++ ++ ++static int ++bsd_commit(void *priv) ++{ ++ return bsd_ctrl_iface(priv, 1); ++} ++ ++ ++static int ++bsd_set_sta_authorized(void *priv, const u8 *addr, ++ unsigned int total_flags, unsigned int flags_or, ++ unsigned int flags_and) ++{ ++ int authorized = -1; ++ ++ /* For now, only support setting Authorized flag */ ++ if (flags_or & WPA_STA_AUTHORIZED) ++ authorized = 1; ++ if (!(flags_and & WPA_STA_AUTHORIZED)) ++ authorized = 0; ++ ++ if (authorized < 0) ++ return 0; ++ ++ return bsd_send_mlme_param(priv, authorized ? ++ IEEE80211_MLME_AUTHORIZE : ++ IEEE80211_MLME_UNAUTHORIZE, 0, addr); ++} ++#else /* HOSTAPD */ ++ ++static int ++get80211param(struct bsd_driver_data *drv, int op) ++{ ++ struct ieee80211req ireq; ++ ++ if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) ++ return -1; ++ return ireq.i_val; ++} ++ ++static int ++wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef SIOCG80211BSSID ++ struct ieee80211_bssid bs; ++ ++ os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); ++ if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) ++ return -1; ++ os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); ++ return 0; ++#else ++ return get80211var(drv, IEEE80211_IOC_BSSID, ++ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; ++#endif ++} ++ ++static int ++wpa_driver_bsd_get_ssid(void *priv, u8 *ssid) ++{ ++ struct bsd_driver_data *drv = priv; ++ return bsd_get_ssid(drv, ssid, 0); ++} ++ ++static int ++wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, ++ size_t wpa_ie_len) ++{ ++#ifdef IEEE80211_IOC_APPIE ++ return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); ++#else /* IEEE80211_IOC_APPIE */ ++ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); ++#endif /* IEEE80211_IOC_APPIE */ ++} ++ ++static int ++wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) ++{ ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", ++ __FUNCTION__, wpa, privacy); ++ ++ if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) ++ ret = -1; ++ if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) ++ ret = -1; ++ if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) ++ ret = -1; ++ ++ return ret; ++} ++ ++static int ++wpa_driver_bsd_set_wpa(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); ++ ++ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); ++} ++ ++static int ++wpa_driver_bsd_set_countermeasures(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); ++} ++ ++ ++static int ++wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) ++{ ++ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); ++ return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); ++} ++ ++static int ++wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) ++{ ++ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, ++ addr); ++} ++ ++static int ++wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) ++{ ++ int authmode; ++ ++ if ((auth_alg & WPA_AUTH_ALG_OPEN) && ++ (auth_alg & WPA_AUTH_ALG_SHARED)) ++ authmode = IEEE80211_AUTH_AUTO; ++ else if (auth_alg & WPA_AUTH_ALG_SHARED) ++ authmode = IEEE80211_AUTH_SHARED; ++ else ++ authmode = IEEE80211_AUTH_OPEN; ++ ++ return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); ++} ++ ++static void ++handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct bsd_driver_data *drv = ctx; ++ ++ drv_event_eapol_rx(drv->ctx, src_addr, buf, len); ++} ++ ++static int ++wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) ++{ ++ struct bsd_driver_data *drv = priv; ++ struct ieee80211req_mlme mlme; ++ u32 mode; ++ int privacy; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, ++ "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" ++ , __func__ ++ , (unsigned int) params->ssid_len, params->ssid ++ , (unsigned int) params->wpa_ie_len ++ , params->pairwise_suite ++ , params->group_suite ++ , params->key_mgmt_suite ++ ); ++ ++ switch (params->mode) { ++ case IEEE80211_MODE_INFRA: ++ mode = 0 /* STA */; ++ break; ++ case IEEE80211_MODE_IBSS: ++ mode = IFM_IEEE80211_IBSS; ++ break; ++ case IEEE80211_MODE_AP: ++ mode = IFM_IEEE80211_HOSTAP; ++ break; ++ default: ++ wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); ++ return -1; ++ } ++ if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ return -1; ++ } ++ ++ if (params->mode == IEEE80211_MODE_AP) { ++ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, ++ handle_read, drv, 0); ++ if (drv->sock_xmit == NULL) ++ return -1; ++ drv->is_ap = 1; ++ return 0; ++ } ++ ++ if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) ++ < 0) ++ ret = -1; ++ if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) ++ ret = -1; ++ /* XXX error handling is wrong but unclear what to do... */ ++ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) ++ return -1; ++ ++ privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && ++ params->group_suite == WPA_CIPHER_NONE && ++ params->key_mgmt_suite == WPA_KEY_MGMT_NONE && ++ params->wpa_ie_len == 0); ++ wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); ++ ++ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) ++ return -1; ++ ++ if (params->wpa_ie_len && ++ set80211param(drv, IEEE80211_IOC_WPA, ++ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) ++ return -1; ++ ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.im_op = IEEE80211_MLME_ASSOC; ++ if (params->ssid != NULL) ++ os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); ++ mlme.im_ssid_len = params->ssid_len; ++ if (params->bssid != NULL) ++ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); ++ if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) ++ return -1; ++ return ret; ++} ++ ++static int ++wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) ++{ ++ struct bsd_driver_data *drv = priv; ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ struct ieee80211_scan_req sr; ++ int i; ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ ++ if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", ++ __func__); ++ return -1; ++ } ++ ++ if (set80211param(drv, IEEE80211_IOC_ROAMING, ++ IEEE80211_ROAMING_MANUAL) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set " ++ "wpa_supplicant-based roaming: %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { ++ wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, ++ strerror(errno)); ++ return -1; ++ } ++ ++ /* NB: interface must be marked UP to do a scan */ ++ if (bsd_ctrl_iface(drv, 1) < 0) ++ return -1; ++ ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ os_memset(&sr, 0, sizeof(sr)); ++ sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | ++ IEEE80211_IOC_SCAN_NOJOIN; ++ sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; ++ if (params->num_ssids > 0) { ++ sr.sr_nssid = params->num_ssids; ++#if 0 ++ /* Boundary check is done by upper layer */ ++ if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) ++ sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; ++#endif ++ ++ /* NB: check scan cache first */ ++ sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; ++ } ++ for (i = 0; i < sr.sr_nssid; i++) { ++ sr.sr_ssid[i].len = params->ssids[i].ssid_len; ++ os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, ++ sr.sr_ssid[i].len); ++ } ++ ++ /* NB: net80211 delivers a scan complete event so no need to poll */ ++ return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); ++#else /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ /* set desired ssid before scan */ ++ if (bsd_set_ssid(drv, params->ssids[0].ssid, ++ params->ssids[0].ssid_len) < 0) ++ return -1; ++ ++ /* NB: net80211 delivers a scan complete event so no need to poll */ ++ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++} ++ ++static void ++wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) ++{ ++ struct bsd_driver_data *drv = sock_ctx; ++ struct if_announcemsghdr *ifan; ++ struct if_msghdr *ifm; ++ struct rt_msghdr *rtm; ++ union wpa_event_data event; ++ struct ieee80211_michael_event *mic; ++ struct ieee80211_leave_event *leave; ++ struct ieee80211_join_event *join; ++ int n; ++ ++ n = read(sock, drv->event_buf, drv->event_buf_len); ++ if (n < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ wpa_printf(MSG_ERROR, "%s read() failed: %s", ++ __func__, strerror(errno)); ++ return; ++ } ++ ++ rtm = (struct rt_msghdr *) drv->event_buf; ++ if (rtm->rtm_version != RTM_VERSION) { ++ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", ++ rtm->rtm_version); ++ return; ++ } ++ os_memset(&event, 0, sizeof(event)); ++ switch (rtm->rtm_type) { ++ case RTM_IFANNOUNCE: ++ ifan = (struct if_announcemsghdr *) rtm; ++ if (ifan->ifan_index != drv->ifindex) ++ break; ++ os_strlcpy(event.interface_status.ifname, drv->ifname, ++ sizeof(event.interface_status.ifname)); ++ switch (ifan->ifan_what) { ++ case IFAN_DEPARTURE: ++ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; ++ default: ++ return; ++ } ++ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", ++ event.interface_status.ifname, ++ ifan->ifan_what == IFAN_DEPARTURE ? ++ "removed" : "added"); ++ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); ++ break; ++ case RTM_IEEE80211: ++ ifan = (struct if_announcemsghdr *) rtm; ++ if (ifan->ifan_index != drv->ifindex) ++ break; ++ switch (ifan->ifan_what) { ++ case RTM_IEEE80211_ASSOC: ++ case RTM_IEEE80211_REASSOC: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); ++ break; ++ case RTM_IEEE80211_DISASSOC: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); ++ break; ++ case RTM_IEEE80211_SCAN: ++ if (drv->is_ap) ++ break; ++ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); ++ break; ++ case RTM_IEEE80211_LEAVE: ++ leave = (struct ieee80211_leave_event *) &ifan[1]; ++ drv_event_disassoc(ctx, leave->iev_addr); ++ break; ++ case RTM_IEEE80211_JOIN: ++#ifdef RTM_IEEE80211_REJOIN ++ case RTM_IEEE80211_REJOIN: ++#endif ++ join = (struct ieee80211_join_event *) &ifan[1]; ++ bsd_new_sta(drv, ctx, join->iev_addr); ++ break; ++ case RTM_IEEE80211_REPLAY: ++ /* ignore */ ++ break; ++ case RTM_IEEE80211_MICHAEL: ++ mic = (struct ieee80211_michael_event *) &ifan[1]; ++ wpa_printf(MSG_DEBUG, ++ "Michael MIC failure wireless event: " ++ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, ++ MAC2STR(mic->iev_src)); ++ ++ os_memset(&event, 0, sizeof(event)); ++ event.michael_mic_failure.unicast = ++ !IEEE80211_IS_MULTICAST(mic->iev_dst); ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, ++ &event); ++ break; ++ } ++ break; ++ case RTM_IFINFO: ++ ifm = (struct if_msghdr *) rtm; ++ if (ifm->ifm_index != drv->ifindex) ++ break; ++ if ((rtm->rtm_flags & RTF_UP) == 0) { ++ os_strlcpy(event.interface_status.ifname, drv->ifname, ++ sizeof(event.interface_status.ifname)); ++ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; ++ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", ++ event.interface_status.ifname); ++ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); ++ } ++ break; ++ } ++} ++ ++static void ++wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, ++ struct ieee80211req_scan_result *sr) ++{ ++ struct wpa_scan_res *result, **tmp; ++ size_t extra_len; ++ u8 *pos; ++ ++ extra_len = 2 + sr->isr_ssid_len; ++ extra_len += 2 + sr->isr_nrates; ++ extra_len += 3; /* ERP IE */ ++ extra_len += sr->isr_ie_len; ++ ++ result = os_zalloc(sizeof(*result) + extra_len); ++ if (result == NULL) ++ return; ++ os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); ++ result->freq = sr->isr_freq; ++ result->beacon_int = sr->isr_intval; ++ result->caps = sr->isr_capinfo; ++ result->qual = sr->isr_rssi; ++ result->noise = sr->isr_noise; ++ /* ++ * the rssi value reported by the kernel is in 0.5dB steps relative to ++ * the reported noise floor. see ieee80211_node.h for details. ++ */ ++ result->level = sr->isr_rssi / 2 + sr->isr_noise; ++ ++ pos = (u8 *)(result + 1); ++ ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = sr->isr_ssid_len; ++ os_memcpy(pos, sr + 1, sr->isr_ssid_len); ++ pos += sr->isr_ssid_len; ++ ++ /* ++ * Deal all rates as supported rate. ++ * Because net80211 doesn't report extended supported rate or not. ++ */ ++ *pos++ = WLAN_EID_SUPP_RATES; ++ *pos++ = sr->isr_nrates; ++ os_memcpy(pos, sr->isr_rates, sr->isr_nrates); ++ pos += sr->isr_nrates; ++ ++ *pos++ = WLAN_EID_ERP_INFO; ++ *pos++ = 1; ++ *pos++ = sr->isr_erp; ++ ++#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ++ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len, ++ sr->isr_ie_len); ++#else ++ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); ++#endif ++ pos += sr->isr_ie_len; ++ ++ result->ie_len = pos - (u8 *)(result + 1); ++ ++ tmp = os_realloc_array(res->res, res->num + 1, ++ sizeof(struct wpa_scan_res *)); ++ if (tmp == NULL) { ++ os_free(result); ++ return; ++ } ++ tmp[res->num++] = result; ++ res->res = tmp; ++} ++ ++struct wpa_scan_results * ++wpa_driver_bsd_get_scan_results2(void *priv) ++{ ++ struct ieee80211req_scan_result *sr; ++ struct wpa_scan_results *res; ++ int len, rest; ++ uint8_t buf[24*1024], *pos; ++ ++ len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); ++ if (len < 0) ++ return NULL; ++ ++ res = os_zalloc(sizeof(*res)); ++ if (res == NULL) ++ return NULL; ++ ++ pos = buf; ++ rest = len; ++ while (rest >= sizeof(struct ieee80211req_scan_result)) { ++ sr = (struct ieee80211req_scan_result *)pos; ++ wpa_driver_bsd_add_scan_entry(res, sr); ++ pos += sr->isr_len; ++ rest -= sr->isr_len; ++ } ++ ++ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", ++ len, (unsigned long)res->num); ++ ++ return res; ++} ++ ++static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) ++{ ++#ifdef IEEE80211_IOC_DEVCAPS ++/* kernel definitions copied from net80211/ieee80211_var.h */ ++#define IEEE80211_CIPHER_WEP 0 ++#define IEEE80211_CIPHER_TKIP 1 ++#define IEEE80211_CIPHER_AES_CCM 3 ++#define IEEE80211_CRYPTO_WEP (1<capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; ++ if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) ++ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104; ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; ++ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; ++ ++ if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) ++ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; ++#undef IEEE80211_CIPHER_WEP ++#undef IEEE80211_CIPHER_TKIP ++#undef IEEE80211_CIPHER_AES_CCM ++#undef IEEE80211_CRYPTO_WEP ++#undef IEEE80211_CRYPTO_TKIP ++#undef IEEE80211_CRYPTO_AES_CCM ++#undef IEEE80211_C_HOSTAP ++#undef IEEE80211_C_WPA1 ++#undef IEEE80211_C_WPA2 ++#else /* IEEE80211_IOC_DEVCAPS */ ++ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ ++ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104 | ++ WPA_DRIVER_CAPA_ENC_TKIP | ++ WPA_DRIVER_CAPA_ENC_CCMP; ++ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; ++#endif /* IEEE80211_IOC_DEVCAPS */ ++#ifdef IEEE80211_IOC_SCAN_MAX_SSID ++ drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; ++#else /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ drv->capa.max_scan_ssids = 1; ++#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ ++ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | ++ WPA_DRIVER_AUTH_SHARED | ++ WPA_DRIVER_AUTH_LEAP; ++ return 0; ++} ++ ++static enum ieee80211_opmode ++get80211opmode(struct bsd_driver_data *drv) ++{ ++ struct ifmediareq ifmr; ++ ++ (void) memset(&ifmr, 0, sizeof(ifmr)); ++ (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); ++ ++ if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { ++ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { ++ if (ifmr.ifm_current & IFM_FLAG0) ++ return IEEE80211_M_AHDEMO; ++ else ++ return IEEE80211_M_IBSS; ++ } ++ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) ++ return IEEE80211_M_HOSTAP; ++ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) ++ return IEEE80211_M_MONITOR; ++#ifdef IEEE80211_M_MBSS ++ if (ifmr.ifm_current & IFM_IEEE80211_MBSS) ++ return IEEE80211_M_MBSS; ++#endif /* IEEE80211_M_MBSS */ ++ } ++ return IEEE80211_M_STA; ++} ++ ++static void * ++wpa_driver_bsd_init(void *ctx, const char *ifname) ++{ ++#define GETPARAM(drv, param, v) \ ++ (((v) = get80211param(drv, param)) != -1) ++ struct bsd_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(*drv)); ++ if (drv == NULL) ++ return NULL; ++ ++ drv->event_buf_len = rtbuf_len(); ++ ++ drv->event_buf = os_malloc(drv->event_buf_len); ++ if (drv->event_buf == NULL) { ++ wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); ++ goto fail1; ++ } ++ ++ /* ++ * NB: We require the interface name be mappable to an index. ++ * This implies we do not support having wpa_supplicant ++ * wait for an interface to appear. This seems ok; that ++ * doesn't belong here; it's really the job of devd. ++ */ ++ drv->ifindex = if_nametoindex(ifname); ++ if (drv->ifindex == 0) { ++ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", ++ __func__, ifname); ++ goto fail1; ++ } ++ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->sock < 0) ++ goto fail1; ++ ++ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); ++ /* Down interface during setup. */ ++ if (bsd_ctrl_iface(drv, 0) < 0) ++ goto fail; ++ ++ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (drv->route < 0) ++ goto fail; ++ eloop_register_read_sock(drv->route, ++ wpa_driver_bsd_event_receive, ctx, drv); ++ ++ drv->ctx = ctx; ++ ++ if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { ++ wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", ++ __func__, strerror(errno)); ++ goto fail; ++ } ++ ++ if (wpa_driver_bsd_capa(drv)) ++ goto fail; ++ ++ drv->opmode = get80211opmode(drv); ++ ++ return drv; ++fail: ++ close(drv->sock); ++fail1: ++ os_free(drv->event_buf); ++ os_free(drv); ++ return NULL; ++#undef GETPARAM ++} ++ ++static void ++wpa_driver_bsd_deinit(void *priv) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ wpa_driver_bsd_set_wpa(drv, 0); ++ eloop_unregister_read_sock(drv->route); ++ ++ /* NB: mark interface down */ ++ bsd_ctrl_iface(drv, 0); ++ ++ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); ++ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) ++ wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", ++ __func__); ++ ++ if (drv->sock_xmit != NULL) ++ l2_packet_deinit(drv->sock_xmit); ++ (void) close(drv->route); /* ioctl socket */ ++ (void) close(drv->sock); /* event socket */ ++ os_free(drv->event_buf); ++ os_free(drv); ++} ++ ++static int ++wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) ++{ ++ struct bsd_driver_data *drv = priv; ++ ++ os_memcpy(capa, &drv->capa, sizeof(*capa)); ++ return 0; ++} ++#endif /* HOSTAPD */ ++ ++ ++const struct wpa_driver_ops wpa_driver_bsd_ops = { ++ .name = "bsd", ++ .desc = "BSD 802.11 support", ++#ifdef HOSTAPD ++ .hapd_init = bsd_init, ++ .hapd_deinit = bsd_deinit, ++ .set_privacy = bsd_set_privacy, ++ .get_seqnum = bsd_get_seqnum, ++ .flush = bsd_flush, ++ .read_sta_data = bsd_read_sta_driver_data, ++ .sta_disassoc = bsd_sta_disassoc, ++ .sta_deauth = bsd_sta_deauth, ++ .sta_set_flags = bsd_set_sta_authorized, ++ .commit = bsd_commit, ++#else /* HOSTAPD */ ++ .init = wpa_driver_bsd_init, ++ .deinit = wpa_driver_bsd_deinit, ++ .get_bssid = wpa_driver_bsd_get_bssid, ++ .get_ssid = wpa_driver_bsd_get_ssid, ++ .set_countermeasures = wpa_driver_bsd_set_countermeasures, ++ .scan2 = wpa_driver_bsd_scan, ++ .get_scan_results2 = wpa_driver_bsd_get_scan_results2, ++ .deauthenticate = wpa_driver_bsd_deauthenticate, ++ .associate = wpa_driver_bsd_associate, ++ .get_capa = wpa_driver_bsd_get_capa, ++#endif /* HOSTAPD */ ++ .set_freq = bsd_set_freq, ++ .set_key = bsd_set_key, ++ .set_ieee8021x = bsd_set_ieee8021x, ++ .hapd_set_ssid = bsd_set_ssid, ++ .hapd_get_ssid = bsd_get_ssid, ++ .hapd_send_eapol = bsd_send_eapol, ++ .set_generic_elem = bsd_set_opt_ie, ++}; +diff --git a/src/drivers/driver_rtl.h b/src/drivers/driver_rtl.h +new file mode 100644 +index 0000000..2200e18 +--- /dev/null ++++ b/src/drivers/driver_rtl.h +@@ -0,0 +1,114 @@ ++ ++#ifndef _DRIVER_RTL_H_ ++#define _DRIVER_RTL_H_ ++ ++ ++#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) ++ ++#define IEEE_CRYPT_ALG_NAME_LEN (16) ++ ++/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */ ++enum { ++ RTL871X_HOSTAPD_FLUSH = 1, ++ RTL871X_HOSTAPD_ADD_STA = 2, ++ RTL871X_HOSTAPD_REMOVE_STA = 3, ++ RTL871X_HOSTAPD_GET_INFO_STA = 4, ++ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ ++ RTL871X_HOSTAPD_GET_WPAIE_STA = 5, ++ RTL871X_SET_ENCRYPTION = 6, ++ RTL871X_GET_ENCRYPTION = 7, ++ RTL871X_HOSTAPD_SET_FLAGS_STA = 8, ++ RTL871X_HOSTAPD_GET_RID = 9, ++ RTL871X_HOSTAPD_SET_RID = 10, ++ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11, ++ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12, ++ RTL871X_HOSTAPD_MLME = 13, ++ RTL871X_HOSTAPD_SCAN_REQ = 14, ++ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15, ++ RTL871X_HOSTAPD_SET_BEACON = 16, ++ RTL871X_HOSTAPD_SET_WPS_BEACON = 17, ++ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18, ++ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19, ++ RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20, ++}; ++ ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ struct { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u8 tx_supp_rates[16]; ++ //struct ieee80211_ht_capability ht_cap; ++ struct ieee80211_ht_capabilities ht_cap; ++ } add_sta; ++ struct { ++ u8 reserved[2];//for set max_num_sta ++ u8 buf[0]; ++ } bcn_ie; ++ ++ } u; ++ ++} ieee_param; ++ ++ ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_OFDM_RATE_LEN 8 ++ ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++ ++#endif ++ +diff --git a/src/drivers/driver_rtw.c b/src/drivers/driver_rtw.c +new file mode 100644 +index 0000000..436dd14 +--- /dev/null ++++ b/src/drivers/driver_rtw.c +@@ -0,0 +1,1993 @@ ++/* ++ * hostapd / Driver interface for rtl871x driver ++ * Copyright (c) 2010, ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Alternatively, this software may be distributed under the terms of BSD ++ * license. ++ * ++ * See README and COPYING for more details. ++ */ ++ ++//#define CONFIG_MGNT_L2SOCK 1 ++#define CONFIG_MLME_OFFLOAD 1 ++ ++ ++#include "includes.h" ++#include ++#include ++ ++#include "common.h" ++ ++/*#include "wireless_copy.h"*/ ++#include "linux_wext.h" ++ ++#include "driver.h" ++#include "eloop.h" ++#include "priv_netlink.h" ++#include "l2_packet/l2_packet.h" ++#include "common/ieee802_11_defs.h" ++#include "netlink.h" ++#include "linux_ioctl.h" ++ ++//#include "../src/ap/hostapd.h" ++//#include "../src/ap/ap_config.h" ++#include "ap/hostapd.h" ++#include "ap/ap_config.h" ++ ++#ifdef USE_KERNEL_HEADERS ++/* compat-wireless does not include linux/compiler.h to define __user, so ++ * define it here */ ++#ifndef __user ++#define __user ++#endif /* __user */ ++#include ++#include ++#include /* The L2 protocols */ ++#include ++#include ++#else /* USE_KERNEL_HEADERS */ ++#include ++#include ++//#include "wireless_copy.h" ++#endif /* USE_KERNEL_HEADERS */ ++ ++//#include ++ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW 0x0019 ++#endif ++ ++#if 0 ++#include "hostapd.h" ++#include "driver.h" ++#include "ieee802_1x.h" ++#include "eloop.h" ++#include "priv_netlink.h" ++#include "sta_info.h" ++#include "l2_packet/l2_packet.h" ++ ++#include "wpa.h" ++#include "accounting.h" ++#include "ieee802_11.h" ++#include "hw_features.h" ++#include "radius/radius.h" ++#endif ++ ++#include "driver_rtl.h" ++ ++ ++//static int rtl871x_sta_remove_ops(void *priv, const u8 *addr); ++ ++struct rtl871x_driver_data { ++ struct hostapd_data *hapd; ++ ++ char iface[IFNAMSIZ + 1]; ++ int ifindex; ++ struct l2_packet_data *l2_sock;/* socket for sending eapol frames*/ ++ struct l2_packet_data *l2_sock_recv;/* raw packet recv socket from bridge interface*/ ++#ifdef CONFIG_MGNT_L2SOCK ++ struct l2_packet_data *mgnt_l2_sock; /* socket for tx/rx management frames*/ ++#else ++ int mgnt_sock;/* socket for tx/rx management frames*/ ++#endif ++ int ioctl_sock; /* socket for ioctl() use */ ++ int wext_sock; /* socket for wireless events */ ++ ++ struct netlink_data *netlink; ++ ++ int we_version; ++ ++ u8 hw_mac[ETH_ALEN]; ++ ++ u8 acct_mac[ETH_ALEN]; ++ ++ struct hostap_sta_driver_data acct_data; ++ ++}; ++ ++/* ++static const char *ether_sprintf(const u8 *addr) ++{ ++ static char buf[sizeof(MACSTR)]; ++ ++ if (addr != NULL) ++ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); ++ else ++ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); ++ ++ return buf; ++} ++*/ ++ ++#ifndef CONFIG_MLME_OFFLOAD ++static int rtl871x_set_iface_flags(void *priv, int dev_up) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ struct ifreq ifr; ++ ++ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); ++ ++ if (drv->mgnt_sock < 0) ++ return -1; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ //os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); ++ //os_strlcpy(ifr.ifr_name, "mgnt.wlan", IFNAMSIZ); ++ snprintf(ifr.ifr_name, IFNAMSIZ, "mgnt.%s", "wlan0"); ++ ++ if (ioctl(drv->mgnt_sock, SIOCGIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCGIFFLAGS]"); ++ return -1; ++ } ++ ++ if (dev_up) ++ ifr.ifr_flags |= IFF_UP; ++ else ++ ifr.ifr_flags &= ~IFF_UP; ++ ++ if (ioctl(drv->mgnt_sock, SIOCSIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCSIFFLAGS]"); ++ return -1; ++ } ++ ++#if 0 ++ if (dev_up) { ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); ++ ifr.ifr_mtu = HOSTAPD_MTU; ++ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { ++ perror("ioctl[SIOCSIFMTU]"); ++ printf("Setting MTU failed - trying to survive with " ++ "current value\n"); ++ } ++ } ++#endif ++ ++ return 0; ++} ++#endif ++ ++static int rtl871x_hostapd_ioctl(struct rtl871x_driver_data *drv, ieee_param *param, int len) ++{ ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) param; ++ iwr.u.data.length = len; ++ ++ if (ioctl(drv->ioctl_sock, RTL_IOCTL_HOSTAPD, &iwr) < 0) { ++ perror("ioctl[RTL_IOCTL_HOSTAPD]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int rtl871x_set_mode(struct rtl871x_driver_data *drv, u32 mode) ++{ ++ struct iwreq iwr; ++ ++ if (drv->ioctl_sock < 0) ++ return -1; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ ++ //iwr.u.mode = IW_MODE_MASTER; ++ iwr.u.mode = mode; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { ++ perror("ioctl[SIOCSIWMODE]"); ++ printf("Could not set interface to mode(%d)!\n", mode); ++ return -1; ++ } ++ ++ return 0; ++ ++} ++ ++/* ++static int rtl871x_notif_assoc(struct hostapd_data *hapd, const u8 *addr, ++ const u8 *ie, size_t ielen) ++{ ++ struct sta_info *sta; ++ int new_assoc, res; ++ ++ //hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, ++ // HOSTAPD_LEVEL_INFO, "associated"); ++ ++ sta = ap_get_sta(hapd, addr); ++ if (sta) { ++ accounting_sta_stop(hapd, sta); ++ } else { ++ sta = ap_sta_add(hapd, addr); ++ if (sta == NULL) ++ { ++ rtl871x_sta_remove_ops(hapd->drv_priv, addr); ++ return -1; ++ } ++ } ++ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); ++ ++ if (hapd->conf->wpa) { ++ if (ie == NULL || ielen == 0) { ++ if (hapd->conf->wps_state) { ++ 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; ++ } ++ ++ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); ++ return -1; ++ } ++ if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && ++ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { ++ sta->flags |= WLAN_STA_WPS; ++ goto skip_wpa_check; ++ } ++ ++ if (sta->wpa_sm == NULL) ++ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, ++ sta->addr); ++ if (sta->wpa_sm == NULL) { ++ 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, NULL, 0); ++ if (res != WPA_IE_OK) { ++ wpa_printf(MSG_DEBUG, "WPA/RSN information element " ++ "rejected? (res %u)", res); ++ wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); ++ return -1; ++ } ++ } else if (hapd->conf->wps_state) { ++ if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && ++ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { ++ sta->flags |= WLAN_STA_WPS; ++ } else ++ sta->flags |= WLAN_STA_MAYBE_WPS; ++ } ++skip_wpa_check: ++ ++ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; ++ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; ++ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); ++ ++ hostapd_new_assoc_sta(hapd, sta, !new_assoc); ++ ++ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); ++ ++ return 0; ++} ++*/ ++ ++static int rtl871x_get_sta_wpaie(struct rtl871x_driver_data *drv, u8 *iebuf, u8 *addr) ++{ ++ struct ieee_param param; ++ ++ printf("+%s, " MACSTR " is sta's address\n", __func__, MAC2STR(addr)); ++ ++ memset(¶m, 0, sizeof(param)); ++ ++ param.cmd = RTL871X_HOSTAPD_GET_WPAIE_STA; ++ ++ memcpy(param.sta_addr, addr, ETH_ALEN); ++ ++ if (rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param))) { ++ printf("Could not get sta wpaie from kernel driver.\n"); ++ return -1; ++ } ++ ++ ++ if(param.u.wpa_ie.len > 32) ++ return -1; ++ ++ memcpy(iebuf, param.u.wpa_ie.reserved, param.u.wpa_ie.len); ++ ++ return 0; ++ ++} ++ ++static int rtl871x_del_sta(struct rtl871x_driver_data *drv, u8 *addr) ++{ ++ struct hostapd_data *hapd = drv->hapd; ++ ++#if 1 ++ ++ //union wpa_event_data event; ++ //os_memset(&event, 0, sizeof(event)); ++ //event.disassoc_info.addr = addr; ++ //wpa_supplicant_event(hapd, EVENT_DISASSOC, &event); ++ ++ drv_event_disassoc(hapd, addr); ++ ++#else ++ ++ struct sta_info *sta; ++ ++ //hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, ++ // HOSTAPD_LEVEL_INFO, "disassociated"); ++ ++ sta = ap_get_sta(hapd, addr); ++ if (sta != NULL) ++ { ++ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); ++ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); ++ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ++ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); ++ ap_free_sta(hapd, sta); ++ } ++ else ++ { ++ wpa_printf(MSG_DEBUG, "Disassociation notification for " ++ "unknown STA " MACSTR, MAC2STR(addr)); ++ } ++#endif ++ ++ return 0; ++ ++} ++ ++static int rtl871x_new_sta(struct rtl871x_driver_data *drv, u8 *addr) ++{ ++ struct hostapd_data *hapd = drv->hapd; ++ //struct ieee80211req_wpaie ie; ++ int ielen = 0, res=0; ++ //u8 *iebuf = NULL; ++ u8 iebuf[32], *piebuf=NULL; ++ ++ /* ++ * Fetch negotiated WPA/RSN parameters from the driver. ++ */ ++ //memset(&ie, 0, sizeof(ie)); ++ //memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); ++ memset(iebuf, 0 , sizeof(iebuf)); ++ if (rtl871x_get_sta_wpaie(drv, iebuf, addr)) { ++ //if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { ++ ++ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", ++ __func__, strerror(errno)); ++ goto no_ie; ++ } ++ ++ //wpa_hexdump(MSG_MSGDUMP, "req WPA IE", ++ // ie.wpa_ie, IEEE80211_MAX_OPT_IE); ++ ++ //wpa_hexdump(MSG_MSGDUMP, "req RSN IE", ++ // ie.rsn_ie, IEEE80211_MAX_OPT_IE); ++ ++ //iebuf = ie.wpa_ie; ++ ++/* ++ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) ++ iebuf[1] = 0; ++ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { ++ iebuf = ie.rsn_ie; ++ if (iebuf[0] != WLAN_EID_RSN) ++ iebuf[1] = 0; ++ } ++*/ ++ ++ if ((iebuf[0] == WLAN_EID_VENDOR_SPECIFIC) || (iebuf[0] == WLAN_EID_RSN) ) ++ { ++ piebuf = iebuf; ++ ielen = iebuf[1]; ++ ++ if (ielen == 0) ++ piebuf = NULL; ++ else ++ ielen += 2; ++ } ++ ++no_ie: ++ ++ //res = rtl871x_notif_assoc(hapd, addr, piebuf, ielen); ++ //drv_event_assoc(hapd, addr, piebuf, ielen); ++ drv_event_assoc(hapd, addr, piebuf, ielen, 0); ++ ++ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { ++ /* Cached accounting data is not valid anymore. */ ++ memset(drv->acct_mac, 0, ETH_ALEN); ++ memset(&drv->acct_data, 0, sizeof(drv->acct_data)); ++ } ++ ++ return res; ++ ++} ++ ++static void rtl871x_wireless_event_wireless(struct rtl871x_driver_data *drv, ++ char *data, int len) ++{ ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom, *buf; ++ ++ pos = data; ++ end = data + len; ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", ++ iwe->cmd, iwe->len); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ return; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (drv->we_version > 18 && ++ (iwe->cmd == IWEVMICHAELMICFAILURE || ++ iwe->cmd == IWEVCUSTOM)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ //printf("got wireless event, iwe->cmd=%d\n", iwe->cmd); ++ ++ switch (iwe->cmd) { ++ case IWEVEXPIRED: ++ rtl871x_del_sta(drv, (u8 *)iwe->u.addr.sa_data); ++ break; ++ case IWEVREGISTERED: ++ if(rtl871x_new_sta(drv, (u8 *)iwe->u.addr.sa_data)) ++ { ++ printf("Failed to add new sta: "MACSTR" \n", MAC2STR((u8 *)iwe->u.addr.sa_data)); ++ } ++ break; ++ case IWEVCUSTOM: ++ if (custom + iwe->u.data.length > end) ++ return; ++ buf = malloc(iwe->u.data.length + 1); ++ if (buf == NULL) ++ return; /* XXX */ ++ memcpy(buf, custom, iwe->u.data.length); ++ buf[iwe->u.data.length] = '\0'; ++ //madwifi_wireless_event_wireless_custom(drv, buf); ++ free(buf); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++ ++} ++ ++#if 1 ++static void rtl871x_wireless_event_rtm_newlink(void *ctx, ++ struct ifinfomsg *ifi, u8 *buf, size_t len) ++{ ++ struct rtl871x_driver_data *drv = ctx; ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ ++ if (ifi->ifi_index != drv->ifindex) ++ return; ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ rtl871x_wireless_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++#else ++static void rtl871x_wireless_event_rtm_newlink(struct rtl871x_driver_data *drv, ++ struct nlmsghdr *h, int len) ++{ ++ struct ifinfomsg *ifi; ++ int attrlen, nlmsg_len, rta_len; ++ struct rtattr * attr; ++ ++ if (len < (int) sizeof(*ifi)) ++ return; ++ ++ ifi = NLMSG_DATA(h); ++ ++ if (ifi->ifi_index != drv->ifindex) ++ return; ++ ++ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); ++ ++ attrlen = h->nlmsg_len - nlmsg_len; ++ if (attrlen < 0) ++ return; ++ ++ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ rtl871x_wireless_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++#endif ++ ++/* ++static void rtl871x_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ char buf[256];//!!! ++ int left; ++ struct sockaddr_nl from; ++ socklen_t fromlen; ++ struct nlmsghdr *h; ++ struct rtl871x_driver_data *drv = eloop_ctx; ++ ++ //printf("+rtl871x_wireless_event_receive\n"); ++ ++ fromlen = sizeof(from); ++ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, ++ (struct sockaddr *) &from, &fromlen); ++ if (left < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ perror("recvfrom(netlink)"); ++ return; ++ } ++ ++ h = (struct nlmsghdr *)buf; ++ while (left >= (int) sizeof(*h)) { ++ int len, plen; ++ ++ len = h->nlmsg_len; ++ plen = len - sizeof(*h);//payload len ++ if (len > left || plen < 0) { ++ printf("Malformed netlink message: " ++ "len=%d left=%d plen=%d\n", ++ len, left, plen); ++ break; ++ } ++ ++ switch (h->nlmsg_type) { ++ case RTM_NEWLINK: ++ rtl871x_wireless_event_rtm_newlink(drv, h, plen); ++ break; ++ } ++ ++ len = NLMSG_ALIGN(len); ++ left -= len; ++ h = (struct nlmsghdr *) ((char *) h + len); ++ } ++ ++ if (left > 0) { ++ printf("%d extra bytes in the end of netlink message\n", left); ++ } ++ ++} ++*/ ++ ++static int rtl871x_wireless_event_init(struct rtl871x_driver_data *drv) ++{ ++ struct netlink_config *cfg; ++ ++ //madwifi_get_we_version(drv); ++ ++ cfg = os_zalloc(sizeof(*cfg)); ++ if (cfg == NULL) ++ return -1; ++ cfg->ctx = drv; ++ cfg->newlink_cb = rtl871x_wireless_event_rtm_newlink; ++ drv->netlink = netlink_init(cfg); ++ if (drv->netlink == NULL) { ++ os_free(cfg); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++static int rtl871x_wireless_event_init_ops(void *priv) ++{ ++ int s; ++ struct sockaddr_nl local; ++ struct rtl871x_driver_data *drv = priv; ++ ++ //madwifi_get_we_version(drv); ++ ++ drv->wext_sock = -1; ++ ++ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); ++ if (s < 0) { ++ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); ++ return -1; ++ } ++ ++ memset(&local, 0, sizeof(local)); ++ local.nl_family = AF_NETLINK; ++ local.nl_groups = RTMGRP_LINK; ++ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { ++ perror("bind(netlink)"); ++ close(s); ++ return -1; ++ } ++ ++ eloop_register_read_sock(s, rtl871x_wireless_event_receive, drv, NULL); ++ drv->wext_sock = s; ++ ++ return 0; ++ ++} ++ ++static void rtl871x_wireless_event_deinit_ops(void *priv) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ ++ if (drv != NULL) { ++ if (drv->wext_sock < 0) ++ return; ++ eloop_unregister_read_sock(drv->wext_sock); ++ close(drv->wext_sock); ++ } ++} ++*/ ++ ++#if 1 ++static void rtl871x_handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct rtl871x_driver_data *drv = ctx; ++ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), ++ len - sizeof(struct l2_ethhdr)); ++} ++#else ++static void rtl871x_handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) ++{ ++ struct rtl871x_driver_data *drv = ctx; ++ struct hostapd_data *hapd = drv->hapd; ++ struct sta_info *sta; ++ ++ sta = ap_get_sta(hapd, src_addr); ++ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { ++ printf("Data frame from not associated STA %s\n", ++ ether_sprintf(src_addr)); ++ /* XXX cannot happen */ ++ return; ++ } ++ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), ++ len - sizeof(struct l2_ethhdr)); ++} ++#endif ++ ++static int rtl871x_send_eapol_ops(void *priv, const u8 *addr, const u8 *data, size_t data_len, ++ int encrypt, const u8 *own_addr, u32 flags) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ unsigned char buf[3000]; ++ unsigned char *bp = buf; ++ struct l2_ethhdr *eth; ++ size_t len; ++ int status; ++ ++ printf("+rtl871x_send_eapol\n"); ++ ++ /* ++ * Prepend the Ethernet header. If the caller left us ++ * space at the front we could just insert it but since ++ * we don't know we copy to a local buffer. Given the frequency ++ * and size of frames this probably doesn't matter. ++ */ ++ len = data_len + sizeof(struct l2_ethhdr); ++ if (len > sizeof(buf)) { ++ bp = malloc(len); ++ if (bp == NULL) { ++ printf("EAPOL frame discarded, cannot malloc temp " ++ "buffer of size %lu!\n", (unsigned long) len); ++ return -1; ++ } ++ } ++ ++ eth = (struct l2_ethhdr *) bp; ++ memcpy(eth->h_dest, addr, ETH_ALEN); ++ memcpy(eth->h_source, own_addr, ETH_ALEN); ++ eth->h_proto = htons(ETH_P_EAPOL); ++ memcpy(eth+1, data, data_len); ++ ++ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); ++ ++ status = l2_packet_send(drv->l2_sock, addr, ETH_P_EAPOL, bp, len); ++ ++ if (bp != buf) ++ free(bp); ++ ++ return status; ++ ++} ++ ++#ifndef CONFIG_MLME_OFFLOAD ++static void rtl871x_receive_mgnt(struct rtl871x_driver_data *drv , const u8 *buf, size_t len) ++{ ++ const struct ieee80211_mgmt *mgmt; ++ //const u8 *end, *ie; ++ u16 fc, type, stype; ++ //size_t ie_len; ++ struct hostapd_data *hapd = drv->hapd; ++ ++ //printf("+rtl871x_receive_mgnt, " MACSTR " is our address\n", MAC2STR(hapd->own_addr)); ++ ++ ++#if 0 ++ { ++ int i; ++ for(i=0; iu.probe_req)) ++ return; ++ ++ mgmt = (const struct ieee80211_mgmt *)buf; ++ ++ fc = le_to_host16(mgmt->frame_control); ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++#if 1 ++ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && ++ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) ++ { ++ //printf("MGNT Frame - PROBE_RESP Frame\n"); ++ } ++#endif ++ ++ //end = buf + len; ++ //ie = mgmt->u.probe_req.variable; ++ //ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); ++ //hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len); ++ ++ switch (type) { ++ case WLAN_FC_TYPE_MGMT: ++ if (stype != WLAN_FC_STYPE_BEACON) ++ wpa_printf(MSG_MSGDUMP, "MGMT"); ++ ++ ++ ++ if (stype == WLAN_FC_STYPE_PROBE_REQ) ++ { ++ ++ } ++ else ++ { ++ //printf("rtl871x_receive_mgnt, type=0x%x, stype=0x%x\n", type, stype); ++ } ++ ++ ++ //ieee802_11_mgmt(hapd, (u8 *)buf, len, stype, NULL); ++ ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ printf("rtl871x_receive_mgnt, CTRL\n"); ++ break; ++ case WLAN_FC_TYPE_DATA: ++ printf("rtl871x_receive_mgnt, DATA\n"); ++ //handle_data(hapd, buf, data_len, stype); ++ break; ++ default: ++ printf("unknown frame type %d\n", type); ++ break; ++ } ++ ++ ++} ++ ++#ifdef CONFIG_MGNT_L2SOCK ++static void rtl871x_recvive_mgmt_frame(void *ctx, const u8 *src_addr, const u8 *buf, ++ size_t len) ++{ ++ struct rtl871x_driver_data *drv = ctx; ++ ++ rtl871x_receive_mgnt(drv, buf, len); ++} ++#else ++static void rtl871x_recvive_mgmt_frame(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++#if 0 ++ int len; ++ unsigned char buf[1024]; ++ struct hostapd_data *hapd = (struct hostapd_data *)eloop_ctx; ++ struct rtl871x_driver_data *drv = (struct rtl871x_driver_data *)hapd->drv_priv; ++ ++ len = recv(sock, buf, sizeof(buf), 0); ++ if (len < 0) { ++ perror("recv"); ++ return; ++ } ++ ++ rtl871x_receive_mgnt(drv, buf, len); ++#endif ++} ++ ++static int rtl871x_mgnt_sock_init(struct rtl871x_driver_data *drv, const char *name) ++{ ++ int sock; ++ struct ifreq ifr; ++ struct sockaddr_ll addr; ++ ++ sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); ++ if (sock < 0) { ++ perror("socket[PF_PACKET,SOCK_RAW]"); ++ return -1; ++ } ++ ++ if (eloop_register_read_sock(sock, rtl871x_recvive_mgmt_frame, drv->hapd, NULL)) ++ { ++ printf("Could not register read socket\n"); ++ return -1; ++ } ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ //snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); ++ os_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ++ if (ioctl(sock, SIOCGIFINDEX, &ifr) != 0) { ++ perror("ioctl(SIOCGIFINDEX)"); ++ return -1; ++ } ++ ++ //if (rtl871x_set_iface_flags(drv, 1)) { ++ // return -1; ++ //} ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sll_family = AF_PACKET; ++ addr.sll_ifindex = ifr.ifr_ifindex; ++ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", ++ addr.sll_ifindex); ++ ++ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { ++ perror("bind"); ++ return -1; ++ } ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ++ if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) { ++ perror("ioctl(SIOCGIFHWADDR)"); ++ return -1; ++ } ++ ++ ++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { ++ printf("Invalid HW-addr family 0x%04x\n", ++ ifr.ifr_hwaddr.sa_family); ++ return -1; ++ } ++ ++ //memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); ++ ++ return sock; ++ ++} ++#endif ++#endif ++ ++static void rtl871x_handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, ++ int ok) ++{ ++#if 0 ++ struct ieee80211_hdr *hdr; ++ u16 fc, type, stype; ++ struct sta_info *sta; ++ ++ //printf("%s\n", __func__); ++ ++ hdr = (struct ieee80211_hdr *) buf; ++ fc = le_to_host16(hdr->frame_control); ++ ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ switch (type) { ++ case WLAN_FC_TYPE_MGMT: ++ //printf("MGMT (TX callback) %s\n", ++ // ok ? "ACK" : "fail"); ++ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ printf("CTRL (TX callback) %s\n", ++ ok ? "ACK" : "fail"); ++ break; ++ case WLAN_FC_TYPE_DATA: ++ printf("DATA (TX callback) %s\n", ++ ok ? "ACK" : "fail"); ++ sta = ap_get_sta(hapd, hdr->addr1); ++ if (sta && sta->flags & WLAN_STA_PENDING_POLL) { ++ wpa_printf(MSG_DEBUG, "STA " MACSTR ++ " %s pending activity poll", ++ MAC2STR(sta->addr), ++ ok ? "ACKed" : "did not ACK"); ++ if (ok) ++ sta->flags &= ~WLAN_STA_PENDING_POLL; ++ } ++ if (sta) ++ ieee802_1x_tx_status(hapd, sta, buf, len, ok); ++ break; ++ default: ++ printf("unknown TX callback frame type %d\n", type); ++ break; ++ } ++#endif ++} ++ ++static int rtl871x_send_mgnt(struct rtl871x_driver_data *drv, const void *msg, size_t len) ++{ ++ int res=0; ++ ++ return res; ++} ++ ++static int rtl871x_send_mgmt_frame_ops(void *priv, const void *msg, size_t len, ++ int flags) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ //struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msg; ++ int res=0; ++ ++ //printf("%s\n", __func__); ++ ++ ++ //hdr->frame_control |= host_to_le16(BIT(1));/* Request TX callback */ ++#ifdef CONFIG_MGNT_L2SOCK ++ //res = send(drv->mgnt_l2_sock, msg, len, flags); ++ //res = l2_packet_send(drv->mgnt_l2_sock, addr, ETH_P_EAPOL, msg, len); ++ if(drv->mgnt_l2_sock == NULL) ++ return res; ++ ++ res = l2_packet_send(drv->mgnt_l2_sock, NULL, ETH_P_80211_RAW, msg, len); ++#else ++ ++ if(drv->mgnt_sock < 0) ++ return res; ++ ++ res = send(drv->mgnt_sock, msg, len, flags); ++#endif ++ //hdr->frame_control &= ~host_to_le16(BIT(1)); ++ ++ ++ rtl871x_send_mgnt(drv, msg, len); ++ ++ rtl871x_handle_tx_callback(drv->hapd, (u8*)msg, len, 1); ++ ++ return res; ++ ++} ++ ++/* ++static int rtl871x_driver_send_ether_ops(void *priv, const u8 *dst, const u8 *src, ++ u16 proto, const u8 *data, size_t data_len) ++{ ++ return 0; ++} ++*/ ++ ++static struct hostapd_hw_modes *rtl871x_get_hw_feature_data_ops(void *priv, ++ u16 *num_modes, ++ u16 *flags) ++{ ++ ++#define MAX_NUM_CHANNEL (14) ++#define MAX_NUM_CHANNEL_5G (24) ++ ++ struct hostapd_hw_modes *modes; ++ size_t i; ++ int k; ++ ++ *num_modes = 3; ++ *flags = 0; ++ ++ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); ++ if (modes == NULL) ++ return NULL; ++ ++ //.1 ++ modes[0].mode = HOSTAPD_MODE_IEEE80211G; ++ modes[0].num_channels = MAX_NUM_CHANNEL; ++ modes[0].num_rates = 12; ++ modes[0].channels = ++ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); ++ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); ++ if (modes[0].channels == NULL || modes[0].rates == NULL) ++ goto fail; ++ for (i = 0; i < MAX_NUM_CHANNEL; i++) { ++ modes[0].channels[i].chan = i + 1; ++ modes[0].channels[i].freq = 2412 + 5 * i; ++ modes[0].channels[i].flag = 0; ++ if (i >= 13) ++ modes[0].channels[i].flag = HOSTAPD_CHAN_DISABLED; ++ } ++ modes[0].rates[0] = 10; ++ modes[0].rates[1] = 20; ++ modes[0].rates[2] = 55; ++ modes[0].rates[3] = 110; ++ modes[0].rates[4] = 60; ++ modes[0].rates[5] = 90; ++ modes[0].rates[6] = 120; ++ modes[0].rates[7] = 180; ++ modes[0].rates[8] = 240; ++ modes[0].rates[9] = 360; ++ modes[0].rates[10] = 480; ++ modes[0].rates[11] = 540; ++ ++ ++ //.2 ++ modes[1].mode = HOSTAPD_MODE_IEEE80211B; ++ modes[1].num_channels = MAX_NUM_CHANNEL; ++ modes[1].num_rates = 4; ++ modes[1].channels = ++ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); ++ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); ++ if (modes[1].channels == NULL || modes[1].rates == NULL) ++ goto fail; ++ for (i = 0; i < MAX_NUM_CHANNEL; i++) { ++ modes[1].channels[i].chan = i + 1; ++ modes[1].channels[i].freq = 2412 + 5 * i; ++ modes[1].channels[i].flag = 0; ++ if (i >= 11) ++ modes[1].channels[i].flag = HOSTAPD_CHAN_DISABLED; ++ } ++ modes[1].rates[0] = 10; ++ modes[1].rates[1] = 20; ++ modes[1].rates[2] = 55; ++ modes[1].rates[3] = 110; ++ ++ ++ //.3 ++ modes[2].mode = HOSTAPD_MODE_IEEE80211A; ++#ifdef CONFIG_DRIVER_RTL_DFS ++ modes[2].num_channels = MAX_NUM_CHANNEL_5G; ++#else /* CONFIG_DRIVER_RTL_DFS */ ++ modes[2].num_channels = 9; ++#endif /* CONFIG_DRIVER_RTL_DFS */ ++ ++ modes[2].num_rates = 8; ++ modes[2].channels = os_zalloc(modes[2].num_channels * sizeof(struct hostapd_channel_data)); ++ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); ++ if (modes[2].channels == NULL || modes[2].rates == NULL) ++ goto fail; ++ ++ ++ k = 0; ++ // 5G band1 Channel: 36, 40, 44, 48 ++ for (i=0; i < 4; i++) { ++ modes[2].channels[k].chan = 36+(i*4); ++ modes[2].channels[k].freq = 5180+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++#ifdef CONFIG_DRIVER_RTL_DFS ++ // 5G band2 Channel: 52, 56, 60, 64 ++ for (i=0; i < 4; i++) { ++ modes[2].channels[k].chan = 52+(i*4); ++ modes[2].channels[k].freq = 5260+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++ // 5G band3 Channel: 100, 104, 108. 112, 116, 120, 124, 128, 132, 136, 140 ++ for (i=0; i < 11; i++) { ++ modes[2].channels[k].chan = 100+(i*4); ++ modes[2].channels[k].freq = 5500+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++#endif /* CONFIG_DRIVER_RTL_DFS */ ++ ++ // 5G band4 Channel: 149, 153, 157, 161, 165 ++ for (i=0; i < 5; i++) { ++ modes[2].channels[k].chan = 149+(i*4); ++ modes[2].channels[k].freq = 5745+(i*20); ++ modes[2].channels[k].flag = 0; ++ k++; ++ } ++ ++ modes[2].rates[0] = 60; ++ modes[2].rates[1] = 90; ++ modes[2].rates[2] = 120; ++ modes[2].rates[3] = 180; ++ modes[2].rates[4] = 240; ++ modes[2].rates[5] = 360; ++ modes[2].rates[6] = 480; ++ modes[2].rates[7] = 540; ++ ++ ++ // ++#if 0 ++#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) ++#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) ++#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) ++#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) ++#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) ++#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) ++#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) ++#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) ++#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) ++#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) ++#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) ++#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) ++#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) ++#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) ++#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) ++#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) ++#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) ++#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) ++#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) ++#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) ++#endif ++ ++ //HOSTAPD_MODE_IEEE80211G ++ modes[0].ht_capab = HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET|HT_CAP_INFO_SHORT_GI20MHZ| ++ HT_CAP_INFO_SHORT_GI40MHZ|HT_CAP_INFO_MAX_AMSDU_SIZE|HT_CAP_INFO_DSSS_CCK40MHZ; ++ ++ modes[0].mcs_set[0]= 0xff; ++ modes[0].mcs_set[1]= 0xff; ++ ++ //HOSTAPD_MODE_IEEE80211B ++ modes[1].ht_capab = 0; ++ ++ //HOSTAPD_MODE_IEEE80211A ++ modes[2].ht_capab = modes[0].ht_capab; ++ ++ modes[2].mcs_set[0]= 0xff; ++ modes[2].mcs_set[1]= 0xff; ++ ++ return modes; ++ ++fail: ++ if (modes) { ++ for (i = 0; i < *num_modes; i++) { ++ os_free(modes[i].channels); ++ os_free(modes[i].rates); ++ } ++ os_free(modes); ++ } ++ ++ return NULL; ++ ++} ++ ++#if 0 ++static int rtl871x_sta_add_ops(const char *ifname, void *priv, const u8 *addr, ++ u16 aid, u16 capability, u8 *supp_rates, ++ size_t supp_rates_len, int flags, ++ u16 listen_interval) ++{ ++ ++#if 1 ++ printf("+%s, " MACSTR " is new sta address added\n", __func__, MAC2STR(addr)); ++ return 0; ++#else ++ struct hostap_driver_data *drv = priv; ++ struct prism2_hostapd_param param; ++ int tx_supp_rates = 0; ++ size_t i; ++ ++#define WLAN_RATE_1M BIT(0) ++#define WLAN_RATE_2M BIT(1) ++#define WLAN_RATE_5M5 BIT(2) ++#define WLAN_RATE_11M BIT(3) ++ ++ for (i = 0; i < supp_rates_len; i++) { ++ if ((supp_rates[i] & 0x7f) == 2) ++ tx_supp_rates |= WLAN_RATE_1M; ++ if ((supp_rates[i] & 0x7f) == 4) ++ tx_supp_rates |= WLAN_RATE_2M; ++ if ((supp_rates[i] & 0x7f) == 11) ++ tx_supp_rates |= WLAN_RATE_5M5; ++ if ((supp_rates[i] & 0x7f) == 22) ++ tx_supp_rates |= WLAN_RATE_11M; ++ } ++ ++ memset(¶m, 0, sizeof(param)); ++ param.cmd = PRISM2_HOSTAPD_ADD_STA; ++ memcpy(param.sta_addr, addr, ETH_ALEN); ++ param.u.add_sta.aid = aid; ++ param.u.add_sta.capability = capability; ++ param.u.add_sta.tx_supp_rates = tx_supp_rates; ++ return hostapd_ioctl(drv, ¶m, sizeof(param)); ++#endif ++} ++ ++static int rtl871x_sta_add2_ops(const char *ifname, void *priv, ++ struct hostapd_sta_add_params *params) ++{ ++#if 0 ++ ieee_param param; ++ //int i, tx_supp_rates = 0; ++ struct rtl871x_driver_data *drv = priv; ++ ++ printf("%s\n", __func__); ++ ++ memset(¶m, 0, sizeof(param)); ++ param.cmd = RTL871X_HOSTAPD_ADD_STA; ++ memcpy(param.sta_addr, params->addr, ETH_ALEN); ++ param.u.add_sta.aid = params->aid; ++ param.u.add_sta.capability = params->capability; ++ param.u.add_sta.flags = params->flags; ++ ++ memcpy(param.u.add_sta.tx_supp_rates, params->supp_rates, params->supp_rates_len); ++ ++/* ++ for (i = 0; i < params->supp_rates_len; i++) ++ { ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_1MB) ++ tx_supp_rates |= IEEE80211_CCK_RATE_1MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_2MB) ++ tx_supp_rates |= IEEE80211_CCK_RATE_2MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_5MB) ++ tx_supp_rates |= IEEE80211_CCK_RATE_5MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_11MB) ++ tx_supp_rates |= IEEE80211_CCK_RATE_11MB_MASK; ++ ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_6MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_6MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_9MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_9MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_12MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_12MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_18MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_18MB_MASK; ++ ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_24MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_24MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_36MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_36MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_48MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_48MB_MASK; ++ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_54MB) ++ tx_supp_rates |= IEEE80211_OFDM_RATE_54MB_MASK; ++ ++ } ++ ++ param.u.add_sta.tx_supp_rates = tx_supp_rates; ++*/ ++ ++#ifdef CONFIG_IEEE80211N ++ if (params->ht_capabilities && params->ht_capabilities->length>0) ++ { ++ struct ieee80211_ht_capability *pht_cap = (struct ieee80211_ht_capability *)¶ms->ht_capabilities->data; ++ memcpy((u8*)¶m.u.add_sta.ht_cap, (u8*)pht_cap, sizeof(struct ieee80211_ht_capability)); ++ ++ } ++#endif /* CONFIG_IEEE80211N */ ++ ++ return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); ++#else ++ return 0; ++#endif ++} ++#endif ++ ++static int rtl871x_sta_remove_ops(void *priv, const u8 *addr) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ struct ieee_param param; ++ ++ printf("+%s, " MACSTR " is sta address removed\n", __func__, MAC2STR(addr)); ++ ++ //hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED); ++ ++ memset(¶m, 0, sizeof(param)); ++ param.cmd = RTL871X_HOSTAPD_REMOVE_STA; ++ memcpy(param.sta_addr, addr, ETH_ALEN); ++ if (rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param))) { ++ printf("Could not remove station from kernel driver.\n"); ++ return -1; ++ } ++ ++ return 0; ++ ++} ++ ++#define RTL871X_HIDDEN_SSID_SUPPORT ++#ifdef RTL871X_HIDDEN_SSID_SUPPORT ++static int rtl871x_set_hidden_ssid_ops(const char *iface, void *priv, u8 value) ++{ ++ int ret; ++ ieee_param pparam; ++ struct rtl871x_driver_data *drv = priv; ++ struct hostapd_data *hapd = drv->hapd; ++ ++ printf("%s\n", __func__); ++ ++ pparam.cmd = RTL871X_HOSTAPD_SET_HIDDEN_SSID; ++ pparam.u.wpa_param.name = 0; ++ pparam.u.wpa_param.value = value; ++ ++ ret = rtl871x_hostapd_ioctl(drv, &pparam, sizeof(ieee_param)); ++ ++ return ret; ++} ++ ++static const u8 * get_ie(u8 *ies, size_t ies_len, u8 id) ++{ ++ const u8 *end, *pos; ++ ++ pos = ies; ++ end = pos + ies_len; ++ ++ while (pos + 1 < end) { ++ if (pos + 2 + pos[1] > end) ++ break; ++ ++ //printf("id:%u, clen:%u\n", pos[0], pos[1]); ++ ++ if (pos[0] == id) ++ return pos; ++ pos += 2 + pos[1]; ++ } ++ ++ return NULL; ++} ++#endif //RTL871X_HIDDEN_SSID_SUPPORT ++ ++static int rtl871x_set_beacon_ops(void *priv, struct wpa_driver_ap_params *params) ++{ ++ int ret; ++ size_t sz; ++ ieee_param *pparam; ++ struct rtl871x_driver_data *drv = priv; ++ struct hostapd_data *hapd = drv->hapd; ++ ++ u8 *ssid_ie; ++ u8 ssid_len; ++ u8 expend_len = 0; ++ ++ if((params->head_len<24) ||(!params->head)) ++ return -1; ++ ++ printf("%s\n", __func__); ++ ++ ++#ifdef RTL871X_HIDDEN_SSID_SUPPORT ++ rtl871x_set_hidden_ssid_ops(drv->iface, priv, hapd->conf->ignore_broadcast_ssid); ++ ++ ssid_ie = get_ie((params->head+24+12), (params->head_len-24-12), WLAN_EID_SSID); ++ ++ if(hapd->conf->ignore_broadcast_ssid == 2) ++ { ++ ssid_len = ssid_ie[1]; ++ ++ //confirm the ssid_len ++ if(ssid_len != hapd->conf->ssid.ssid_len) ++ { ++ printf("%s ssid_len(%u) != hapd->conf->ssid.ssid_len(%u)!!\n", __func__ ++ , ssid_len, hapd->conf->ssid.ssid_len ++ ); ++ } ++ ++ memcpy(ssid_ie+2, hapd->conf->ssid.ssid, ssid_len); ++ } ++ else if(hapd->conf->ignore_broadcast_ssid == 1) ++ { ++ expend_len = hapd->conf->ssid.ssid_len; ++ printf("%s ignore_broadcast_ssid:%d, %s,%d, expend_len:%u\n", __func__ ++ , hapd->conf->ignore_broadcast_ssid ++ , hapd->conf->ssid.ssid ++ , hapd->conf->ssid.ssid_len ++ , expend_len ++ ); ++ } ++#endif //RTL871X_HIDDEN_SSID_SUPPORT ++ ++ sz = params->head_len+params->tail_len+12-24 + 2 + expend_len;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed ++ pparam = os_zalloc(sz); ++ if (pparam == NULL) { ++ return -ENOMEM; ++ } ++ ++ pparam->cmd = RTL871X_HOSTAPD_SET_BEACON; ++ ++ memcpy(pparam->u.bcn_ie.reserved, &hapd->conf->max_num_sta, 2);//for set max_num_sta ++ ++#ifdef RTL871X_HIDDEN_SSID_SUPPORT ++ if(hapd->conf->ignore_broadcast_ssid == 1) ++ { ++ u8 *ssid_ie_next = params->head+24+12+2; ++ size_t head_remain_len = params->head_len-24-12-2; ++ ++ memcpy(pparam->u.bcn_ie.buf, (params->head+24), 12); ++ ++ pparam->u.bcn_ie.buf[12] = WLAN_EID_SSID; ++ pparam->u.bcn_ie.buf[13] = expend_len; ++ memcpy(pparam->u.bcn_ie.buf+12+2, hapd->conf->ssid.ssid, expend_len); ++ ++ memcpy(pparam->u.bcn_ie.buf+12+2+expend_len, ssid_ie_next, head_remain_len);// 24=beacon header len. ++ memcpy(&pparam->u.bcn_ie.buf[params->head_len-24+expend_len], params->tail, params->tail_len); ++ } ++ else ++#endif //RTL871X_HIDDEN_SSID_SUPPORT ++ { ++ memcpy(pparam->u.bcn_ie.buf, (params->head+24), (params->head_len-24));// 24=beacon header len. ++ memcpy(&pparam->u.bcn_ie.buf[params->head_len-24], params->tail, params->tail_len); ++ } ++ ++ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); ++ ++ os_free(pparam); ++ ++ //rtl871x_set_max_num_sta(drv); ++ ++ return ret; ++ ++} ++ ++/* ++enum wpa_alg { ++ WPA_ALG_NONE, ++ WPA_ALG_WEP, ++ WPA_ALG_TKIP, ++ WPA_ALG_CCMP, ++ WPA_ALG_IGTK, ++ WPA_ALG_PMK ++}; ++*/ ++static int rtl871x_set_key_ops(const char *ifname, void *priv, enum wpa_alg alg, ++ const u8 *addr, int idx, int txkey, const u8 *seq, ++ size_t seq_len, const u8 *key, size_t key_len) ++{ ++ ieee_param *param; ++ u8 *buf; ++ char *alg_str; ++ size_t blen; ++ int ret = 0; ++ struct rtl871x_driver_data *drv = priv; ++ ++ printf("%s\n", __func__); ++ ++ blen = sizeof(*param) + key_len; ++ buf = os_zalloc(blen); ++ if (buf == NULL) ++ return -1; ++ ++ param = (ieee_param *)buf; ++ param->cmd = RTL871X_SET_ENCRYPTION; ++ if (addr == NULL) ++ memset(param->sta_addr, 0xff, ETH_ALEN); ++ else ++ memcpy(param->sta_addr, addr, ETH_ALEN); ++ ++ ++ switch (alg) { ++ case WPA_ALG_NONE: ++ alg_str = "none"; ++ break; ++ case WPA_ALG_WEP: ++ //cipher = IEEE80211_CIPHER_WEP; ++ alg_str = "WEP"; ++ break; ++ case WPA_ALG_TKIP: ++ //cipher = IEEE80211_CIPHER_TKIP; ++ alg_str = "TKIP"; ++ break; ++ case WPA_ALG_CCMP: ++ //cipher = IEEE80211_CIPHER_AES_CCM; ++ alg_str = "CCMP"; ++ break; ++ default: ++ printf("%s: unknown/unsupported algorithm %d\n", ++ __func__, alg); ++ return -1; ++ } ++ ++ os_strlcpy((char *) param->u.crypt.alg, alg_str, ++ IEEE_CRYPT_ALG_NAME_LEN); ++ ++ //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; ++ param->u.crypt.set_tx = txkey ? 1 : 0; ++ param->u.crypt.idx = idx; ++ param->u.crypt.key_len = key_len; ++ ++ //memcpy((u8 *) (param + 1), key, key_len); ++ memcpy(param->u.crypt.key, key, key_len); ++ ++ if (rtl871x_hostapd_ioctl(drv, param, blen)) { ++ printf("Failed to set encryption.\n"); ++ ret = -1; ++ } ++ ++ os_free(buf); ++ ++ return ret; ++ ++} ++ ++/* ++static int rtl871x_set_encryption_ops(const char *ifname, void *priv, ++ const char *alg, const u8 *addr, ++ int idx, const u8 *key, size_t key_len, ++ int txkey) ++{ ++ ieee_param *param; ++ u8 *buf; ++ size_t blen; ++ int ret = 0; ++ struct rtl871x_driver_data *drv = priv; ++ ++ printf("%s\n", __func__); ++#if 0 ++ blen = sizeof(*param) + key_len; ++ buf = os_zalloc(blen); ++ if (buf == NULL) ++ return -1; ++ ++ param = (ieee_param *)buf; ++ param->cmd = RTL871X_SET_ENCRYPTION; ++ if (addr == NULL) ++ memset(param->sta_addr, 0xff, ETH_ALEN); ++ else ++ memcpy(param->sta_addr, addr, ETH_ALEN); ++ ++ os_strlcpy((char *) param->u.crypt.alg, alg, ++ IEEE_CRYPT_ALG_NAME_LEN); ++ ++ //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; ++ param->u.crypt.set_tx = txkey ? 1 : 0; ++ param->u.crypt.idx = idx; ++ param->u.crypt.key_len = key_len; ++ ++ //memcpy((u8 *) (param + 1), key, key_len); ++ memcpy(param->u.crypt.key, key, key_len); ++ ++ if (rtl871x_hostapd_ioctl(drv, param, blen)) { ++ printf("Failed to set encryption.\n"); ++ ret = -1; ++ } ++ ++ os_free(buf); ++#endif ++ return ret; ++ ++} ++*/ ++ ++//static int rtl871x_sta_deauth_ops(void *priv, const u8 *addr, int reason) ++static int rtl871x_sta_deauth_ops(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason) ++{ ++ printf("+%s, " MACSTR " is deauth, reason=%d\n", __func__, MAC2STR(addr), reason); ++ ++ //struct hostap_driver_data *drv = priv; ++ struct rtl871x_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DEAUTH); ++ ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.sa, own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, own_addr, ETH_ALEN); ++ mgmt.u.deauth.reason_code = host_to_le16(reason); ++ ++ return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.deauth), 0); ++ ++} ++ ++ ++//static int rtl871x_sta_disassoc_ops(void *priv, const u8 *addr, int reason) ++static int rtl871x_sta_disassoc_ops(void *priv, const u8 *own_addr, const u8 *addr, ++ int reason) ++{ ++ printf("+%s, " MACSTR " is disassoc, reason=%d\n", __func__, MAC2STR(addr), reason); ++ ++ struct rtl871x_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DISASSOC); ++ ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.sa, own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, own_addr, ETH_ALEN); ++ ++ mgmt.u.disassoc.reason_code = host_to_le16(reason); ++ ++ return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.disassoc), 0); ++ ++} ++ ++static int rtl871x_set_wps_assoc_resp_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) ++{ ++ int ret; ++ size_t sz; ++ ieee_param *pparam; ++ ++ ++ printf("%s\n", __func__); ++ ++ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed ++ pparam = os_zalloc(sz); ++ if (pparam == NULL) { ++ return -ENOMEM; ++ } ++ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP; ++ ++ if(ie && len>0) ++ { ++ memcpy(pparam->u.bcn_ie.buf, ie, len); ++ } ++ ++ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); ++ ++ os_free(pparam); ++ ++ return ret; ++ ++} ++ ++static int rtl871x_set_wps_beacon_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) ++{ ++ int ret; ++ size_t sz; ++ ieee_param *pparam; ++ ++ ++ printf("%s\n", __func__); ++ ++ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed ++ pparam = os_zalloc(sz); ++ if (pparam == NULL) { ++ return -ENOMEM; ++ } ++ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_BEACON; ++ ++ if(ie && len>0) ++ { ++ memcpy(pparam->u.bcn_ie.buf, ie, len); ++ } ++ ++ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); ++ ++ os_free(pparam); ++ ++ return ret; ++ ++} ++ ++static int rtl871x_set_wps_probe_resp_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) ++{ ++ int ret; ++ size_t sz; ++ ieee_param *pparam; ++ ++ ++ printf("%s\n", __func__); ++ ++ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed ++ pparam = os_zalloc(sz); ++ if (pparam == NULL) { ++ return -ENOMEM; ++ } ++ ++ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_PROBE_RESP; ++ ++ if(ie && len>0) ++ { ++ memcpy(pparam->u.bcn_ie.buf, ie, len); ++ } ++ ++ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); ++ ++ os_free(pparam); ++ ++ return ret; ++ ++} ++ ++static int rtl871x_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, ++ const struct wpabuf *proberesp, const struct wpabuf *assocresp) ++{ ++ struct rtl871x_driver_data *drv = priv; ++ ++ if (rtl871x_set_wps_assoc_resp_ie(drv, assocresp ? wpabuf_head(assocresp) : NULL, ++ assocresp ? wpabuf_len(assocresp) : 0)) ++ return -1; ++ ++ if (rtl871x_set_wps_beacon_ie(drv, beacon ? wpabuf_head(beacon) : NULL, ++ beacon ? wpabuf_len(beacon) : 0)) ++ return -1; ++ ++ return rtl871x_set_wps_probe_resp_ie(drv, ++ proberesp ? wpabuf_head(proberesp) : NULL, ++ proberesp ? wpabuf_len(proberesp): 0); ++ ++} ++ ++static int rtl871x_sta_flush_ops(void *priv) ++{ ++ ieee_param param; ++ struct rtl871x_driver_data *drv = priv; ++ ++ memset(¶m, 0, sizeof(param)); ++ ++ param.cmd = RTL871X_HOSTAPD_FLUSH; ++ ++ return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); ++} ++ ++static void *rtl871x_driver_init_ops(struct hostapd_data *hapd, struct wpa_init_params *params) ++{ ++ struct rtl871x_driver_data *drv; ++ struct ifreq ifr; ++ //struct iwreq iwr; ++ char ifrn_name[IFNAMSIZ + 1];//for mgnt_l2_sock/mgnt_sock ++ char brname[IFNAMSIZ]; ++ ++ drv = os_zalloc(sizeof(struct rtl871x_driver_data)); ++ if (drv == NULL) { ++ printf("Could not allocate memory for rtl871x driver data\n"); ++ return NULL; ++ } ++ ++ drv->hapd = hapd; ++ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->ioctl_sock < 0) { ++ perror("socket[PF_INET,SOCK_DGRAM]"); ++ goto bad; ++ } ++ os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); ++ ++ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);/*set interface up*/ ++ ++ os_memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); ++ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { ++ perror("ioctl(SIOCGIFINDEX)"); ++ goto bad; ++ } ++ drv->ifindex = ifr.ifr_ifindex; ++ printf("drv->ifindex=%d\n", drv->ifindex); ++ ++ drv->l2_sock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, ++ rtl871x_handle_read, drv, 1); ++ ++ if (drv->l2_sock == NULL) ++ goto bad; ++ ++ if (l2_packet_get_own_addr(drv->l2_sock, params->own_addr)) ++ goto bad; ++ ++ ++ if (params->bridge[0]) { ++ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", ++ params->bridge[0]); ++ drv->l2_sock_recv = l2_packet_init(params->bridge[0], NULL, ++ ETH_P_EAPOL, rtl871x_handle_read, drv, ++ 1); ++ if (drv->l2_sock_recv == NULL) ++ { ++ //goto bad; ++ drv->l2_sock_recv = drv->l2_sock; ++ printf("no br0 interface , let l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); ++ } ++ ++ } else if (linux_br_get(brname, drv->iface) == 0) { ++ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " ++ "EAPOL receive", brname); ++ drv->l2_sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, ++ rtl871x_handle_read, drv, 1); ++ if (drv->l2_sock_recv == NULL) ++ goto bad; ++ } ++ else ++ { ++ drv->l2_sock_recv = drv->l2_sock; ++ printf("l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); ++ } ++ ++ ++ os_memset(ifrn_name, 0, sizeof(ifrn_name)); ++ //snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s_rena", drv->iface); ++ snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s", "wlan0"/*drv->iface*/); ++#ifdef CONFIG_MGNT_L2SOCK ++ drv->mgnt_l2_sock = NULL; ++ drv->mgnt_l2_sock = l2_packet_init(ifrn_name, NULL, ETH_P_80211_RAW, ++ rtl871x_recvive_mgmt_frame, drv, 1); ++ if (drv->mgnt_l2_sock == NULL) ++ goto bad; ++ ++#else ++ ++#ifdef CONFIG_MLME_OFFLOAD ++ drv->mgnt_sock = -1; ++#else ++ drv->mgnt_sock = rtl871x_mgnt_sock_init(drv, ifrn_name); ++ if (drv->mgnt_sock < 0) { ++ goto bad; ++ } ++#endif ++ ++#endif ++ ++ ++ //madwifi_set_iface_flags(drv, 0); /* mark down during setup */ ++ //madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */ ++ ++ ++ //linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);/*set interface up*/ ++ ++ ++ //enter MASTER MODE when init. ++ if(rtl871x_set_mode(drv, IW_MODE_MASTER)<0) ++ { ++ printf("Could not set interface to master mode!\n"); ++ goto bad; ++ } ++ ++/* ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ iwr.u.mode = IW_MODE_MASTER; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { ++ perror("ioctl[SIOCSIWMODE]"); ++ printf("Could not set interface to master mode!\n"); ++ goto bad; ++ } ++*/ ++ ++#ifndef CONFIG_MLME_OFFLOAD ++ rtl871x_set_iface_flags(drv, 1); /*set mgnt interface up*/ ++#endif ++ ++ ++ if (rtl871x_wireless_event_init(drv)) ++ goto bad; ++ ++ ++ os_memcpy(drv->hw_mac, params->own_addr, ETH_ALEN); ++ ++ return drv; ++ ++bad: ++ ++ if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) ++ l2_packet_deinit(drv->l2_sock_recv); ++ ++ if (drv->l2_sock != NULL) ++ l2_packet_deinit(drv->l2_sock); ++ ++ if (drv->ioctl_sock >= 0) ++ close(drv->ioctl_sock); ++ ++#ifdef CONFIG_MGNT_L2SOCK ++ if ( drv->mgnt_l2_sock != NULL) ++ l2_packet_deinit(drv->mgnt_l2_sock); ++#else ++ if (drv->mgnt_sock >= 0) ++ close(drv->mgnt_sock); ++#endif ++ ++ if (drv != NULL) ++ free(drv); ++ ++ return NULL; ++ ++} ++ ++static void rtl871x_driver_deinit_ops(void *priv) ++{ ++ //struct iwreq iwr; ++ struct rtl871x_driver_data *drv = priv; ++ ++ //back to INFRA MODE when exit. ++/* ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ iwr.u.mode = IW_MODE_INFRA; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { ++ perror("ioctl[SIOCSIWMODE]"); ++ } ++*/ ++ rtl871x_set_mode(drv, IW_MODE_INFRA); ++ ++ ++ if (drv->ioctl_sock >= 0) ++ close(drv->ioctl_sock); ++ ++ ++ if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) ++ l2_packet_deinit(drv->l2_sock_recv); ++ ++ if(drv->l2_sock) ++ l2_packet_deinit(drv->l2_sock); ++ ++ //if (drv->sock_xmit != NULL) ++ // l2_packet_deinit(drv->sock_xmit); ++ ++#ifdef CONFIG_MGNT_L2SOCK ++ if (drv->mgnt_l2_sock) ++ l2_packet_deinit(drv->mgnt_l2_sock); ++#else ++ if (drv->mgnt_sock >= 0) ++ close(drv->mgnt_sock); ++#endif ++ ++ os_free(drv); ++ ++} ++ ++ ++const struct wpa_driver_ops wpa_driver_rtw_ops = { ++ .name = "rtl871xdrv", ++ //.init = rtl871x_driver_init_ops, ++ //.deinit = rtl871x_driver_deinit_ops, ++ .hapd_init = rtl871x_driver_init_ops, ++ .hapd_deinit = rtl871x_driver_deinit_ops, ++ //.wireless_event_init = rtl871x_wireless_event_init_ops, ++ //.wireless_event_deinit = rtl871x_wireless_event_deinit_ops, ++ //.send_eapol = rtl871x_send_eapol_ops, ++ .hapd_send_eapol = rtl871x_send_eapol_ops, ++ //.send_ether = rtl871x_driver_send_ether_ops, ++ //.send_mgmt_frame = rtl871x_send_mgmt_frame_ops, ++ .get_hw_feature_data = rtl871x_get_hw_feature_data_ops, ++ //.sta_add = rtl871x_sta_add_ops, ++ //.sta_add2 = rtl871x_sta_add2_ops, ++ .sta_remove = rtl871x_sta_remove_ops, ++ .set_ap = rtl871x_set_beacon_ops, ++ //.set_encryption = rtl871x_set_encryption_ops, ++ .set_key = rtl871x_set_key_ops, ++ .sta_deauth = rtl871x_sta_deauth_ops, ++ .sta_disassoc = rtl871x_sta_disassoc_ops, ++ //.set_wps_beacon_ie = rtl871x_set_wps_beacon_ie_ops, ++ //.set_wps_probe_resp_ie = rtl871x_set_wps_probe_resp_ie_ops, ++ .set_ap_wps_ie = rtl871x_set_ap_wps_ie, ++ .flush = rtl871x_sta_flush_ops, ++}; ++ +diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c +index 01defdf..1de29c8 100644 +--- a/src/drivers/driver_wext.c ++++ b/src/drivers/driver_wext.c +@@ -1081,6 +1081,38 @@ void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) + wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); + } + ++//added for wps2.0 @20110519 ++static int wpa_driver_wext_set_probe_req_ie(struct wpa_driver_wext_data *drv, const u8 *extra_ies, ++ size_t extra_ies_len) ++{ ++ unsigned char *pbuf; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ pbuf = os_malloc(extra_ies_len); ++ os_memset(pbuf, 0, extra_ies_len); ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ os_memcpy(pbuf, extra_ies, extra_ies_len); ++ ++ iwr.u.data.pointer = (caddr_t)pbuf; ++ iwr.u.data.length = extra_ies_len; ++ iwr.u.data.flags = 0x8766;//magic number ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr) < 0) { ++ perror("ioctl[SIOCSIWMLME]"); ++ ret = -1; ++ } ++ ++ if(pbuf) ++ os_free(pbuf); ++ ++ return ret; ++ ++} ++ + + /** + * wpa_driver_wext_scan - Request the driver to initiate scan +@@ -1103,6 +1135,10 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) + return -1; + } + ++ //added for wps2.0 @20110519 ++ wpa_driver_wext_set_probe_req_ie(drv, params->extra_ies, ++ params->extra_ies_len); ++ + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + +@@ -2403,6 +2439,28 @@ int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, + return 0; + } + ++// Aries 20120120, append rssi information at the end of "status" command ++int wext_signal_poll(void *priv, struct wpa_signal_info *signal_info) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ struct iw_statistics stat; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_memset(&stat, 0, sizeof(stat)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) &stat; ++ iwr.u.data.length = sizeof(struct iw_statistics); ++ iwr.u.data.flags = 1; ++ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { ++ perror("ioctl[SIOCGIWSTATS] fail\n"); ++ ret = -1; ++ } ++ signal_info->current_signal = stat.qual.level; ++ signal_info->current_noise = stat.qual.noise; ++ return ret; ++} + + int wpa_driver_wext_set_operstate(void *priv, int state) + { +diff --git a/src/drivers/driver_wext.c.orig b/src/drivers/driver_wext.c.orig +new file mode 100644 +index 0000000..01defdf +--- /dev/null ++++ b/src/drivers/driver_wext.c.orig +@@ -0,0 +1,2511 @@ ++/* ++ * Driver interaction with generic Linux Wireless Extensions ++ * Copyright (c) 2003-2015, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ * ++ * This file implements a driver interface for the Linux Wireless Extensions. ++ * When used with WE-18 or newer, this interface can be used as-is with number ++ * of drivers. In addition to this, some of the common functions in this file ++ * can be used by other driver interface implementations that use generic WE ++ * ioctls, but require private ioctls for some of the functionality. ++ */ ++ ++#include "includes.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "linux_wext.h" ++#include "common.h" ++#include "eloop.h" ++#include "common/ieee802_11_defs.h" ++#include "common/wpa_common.h" ++#include "priv_netlink.h" ++#include "netlink.h" ++#include "linux_ioctl.h" ++#include "rfkill.h" ++#include "driver.h" ++#include "driver_wext.h" ++ ++static int wpa_driver_wext_flush_pmkid(void *priv); ++static int wpa_driver_wext_get_range(void *priv); ++static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); ++static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); ++static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); ++ ++ ++int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, ++ int idx, u32 value) ++{ ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.param.flags = idx & IW_AUTH_INDEX; ++ iwr.u.param.value = value; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { ++ if (errno != EOPNOTSUPP) { ++ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " ++ "value 0x%x) failed: %s)", ++ idx, value, strerror(errno)); ++ } ++ ret = errno == EOPNOTSUPP ? -2 : -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @bssid: Buffer for BSSID ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_get_bssid(void *priv, u8 *bssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno)); ++ ret = -1; ++ } ++ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @bssid: BSSID ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.ap_addr.sa_family = ARPHRD_ETHER; ++ if (bssid) ++ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); ++ else ++ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @ssid: Buffer for the SSID; must be at least 32 bytes long ++ * Returns: SSID length on success, -1 on failure ++ */ ++int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.essid.pointer = (caddr_t) ssid; ++ iwr.u.essid.length = SSID_MAX_LEN; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", ++ strerror(errno)); ++ ret = -1; ++ } else { ++ ret = iwr.u.essid.length; ++ if (ret > SSID_MAX_LEN) ++ ret = SSID_MAX_LEN; ++ /* Some drivers include nul termination in the SSID, so let's ++ * remove it here before further processing. WE-21 changes this ++ * to explicitly require the length _not_ to include nul ++ * termination. */ ++ if (ret > 0 && ssid[ret - 1] == '\0' && ++ drv->we_version_compiled < 21) ++ ret--; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @ssid: SSID ++ * @ssid_len: Length of SSID (0..32) ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ char buf[33]; ++ ++ if (ssid_len > SSID_MAX_LEN) ++ return -1; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ ++ iwr.u.essid.flags = (ssid_len != 0); ++ os_memset(buf, 0, sizeof(buf)); ++ os_memcpy(buf, ssid, ssid_len); ++ iwr.u.essid.pointer = (caddr_t) buf; ++ if (drv->we_version_compiled < 21) { ++ /* For historic reasons, set SSID length to include one extra ++ * character, C string nul termination, even though SSID is ++ * really an octet string that should not be presented as a C ++ * string. Some Linux drivers decrement the length by one and ++ * can thus end up missing the last octet of the SSID if the ++ * length is not incremented here. WE-21 changes this to ++ * explicitly require the length _not_ to include nul ++ * termination. */ ++ if (ssid_len) ++ ssid_len++; ++ } ++ iwr.u.essid.length = ssid_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @freq: Frequency in MHz ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_freq(void *priv, int freq) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.freq.m = freq * 100000; ++ iwr.u.freq.e = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static void ++wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) ++{ ++ union wpa_event_data data; ++ ++ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", ++ custom); ++ ++ os_memset(&data, 0, sizeof(data)); ++ /* Host AP driver */ ++ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { ++ data.michael_mic_failure.unicast = ++ os_strstr(custom, " unicast ") != NULL; ++ /* TODO: parse parameters(?) */ ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); ++ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { ++ char *spos; ++ int bytes; ++ u8 *req_ies = NULL, *resp_ies = NULL; ++ ++ spos = custom + 17; ++ ++ bytes = strspn(spos, "0123456789abcdefABCDEF"); ++ if (!bytes || (bytes & 1)) ++ return; ++ bytes /= 2; ++ ++ req_ies = os_malloc(bytes); ++ if (req_ies == NULL || ++ hexstr2bin(spos, req_ies, bytes) < 0) ++ goto done; ++ data.assoc_info.req_ies = req_ies; ++ data.assoc_info.req_ies_len = bytes; ++ ++ spos += bytes * 2; ++ ++ data.assoc_info.resp_ies = NULL; ++ data.assoc_info.resp_ies_len = 0; ++ ++ if (os_strncmp(spos, " RespIEs=", 9) == 0) { ++ spos += 9; ++ ++ bytes = strspn(spos, "0123456789abcdefABCDEF"); ++ if (!bytes || (bytes & 1)) ++ goto done; ++ bytes /= 2; ++ ++ resp_ies = os_malloc(bytes); ++ if (resp_ies == NULL || ++ hexstr2bin(spos, resp_ies, bytes) < 0) ++ goto done; ++ data.assoc_info.resp_ies = resp_ies; ++ data.assoc_info.resp_ies_len = bytes; ++ } ++ ++ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); ++ ++ done: ++ os_free(resp_ies); ++ os_free(req_ies); ++#ifdef CONFIG_PEERKEY ++ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { ++ if (hwaddr_aton(custom + 17, data.stkstart.peer)) { ++ wpa_printf(MSG_DEBUG, "WEXT: unrecognized " ++ "STKSTART.request '%s'", custom + 17); ++ return; ++ } ++ wpa_supplicant_event(ctx, EVENT_STKSTART, &data); ++#endif /* CONFIG_PEERKEY */ ++ } ++} ++ ++ ++static int wpa_driver_wext_event_wireless_michaelmicfailure( ++ void *ctx, const char *ev, size_t len) ++{ ++ const struct iw_michaelmicfailure *mic; ++ union wpa_event_data data; ++ ++ if (len < sizeof(*mic)) ++ return -1; ++ ++ mic = (const struct iw_michaelmicfailure *) ev; ++ ++ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " ++ "flags=0x%x src_addr=" MACSTR, mic->flags, ++ MAC2STR(mic->src_addr.sa_data)); ++ ++ os_memset(&data, 0, sizeof(data)); ++ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); ++ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_pmkidcand( ++ struct wpa_driver_wext_data *drv, const char *ev, size_t len) ++{ ++ const struct iw_pmkid_cand *cand; ++ union wpa_event_data data; ++ const u8 *addr; ++ ++ if (len < sizeof(*cand)) ++ return -1; ++ ++ cand = (const struct iw_pmkid_cand *) ev; ++ addr = (const u8 *) cand->bssid.sa_data; ++ ++ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " ++ "flags=0x%x index=%d bssid=" MACSTR, cand->flags, ++ cand->index, MAC2STR(addr)); ++ ++ os_memset(&data, 0, sizeof(data)); ++ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); ++ data.pmkid_candidate.index = cand->index; ++ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; ++ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_assocreqie( ++ struct wpa_driver_wext_data *drv, const char *ev, int len) ++{ ++ if (len < 0) ++ return -1; ++ ++ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, ++ len); ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = os_malloc(len); ++ if (drv->assoc_req_ies == NULL) { ++ drv->assoc_req_ies_len = 0; ++ return -1; ++ } ++ os_memcpy(drv->assoc_req_ies, ev, len); ++ drv->assoc_req_ies_len = len; ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_event_wireless_assocrespie( ++ struct wpa_driver_wext_data *drv, const char *ev, int len) ++{ ++ if (len < 0) ++ return -1; ++ ++ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, ++ len); ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = os_malloc(len); ++ if (drv->assoc_resp_ies == NULL) { ++ drv->assoc_resp_ies_len = 0; ++ return -1; ++ } ++ os_memcpy(drv->assoc_resp_ies, ev, len); ++ drv->assoc_resp_ies_len = len; ++ ++ return 0; ++} ++ ++ ++static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) ++{ ++ union wpa_event_data data; ++ ++ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) ++ return; ++ ++ os_memset(&data, 0, sizeof(data)); ++ if (drv->assoc_req_ies) { ++ data.assoc_info.req_ies = drv->assoc_req_ies; ++ data.assoc_info.req_ies_len = drv->assoc_req_ies_len; ++ } ++ if (drv->assoc_resp_ies) { ++ data.assoc_info.resp_ies = drv->assoc_resp_ies; ++ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; ++ } ++ ++ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); ++ ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = NULL; ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = NULL; ++} ++ ++ ++static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, ++ char *data, int len) ++{ ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom, *buf; ++ ++ pos = data; ++ end = data + len; ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", ++ iwe->cmd, iwe->len); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ return; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (drv->we_version_compiled > 18 && ++ (iwe->cmd == IWEVMICHAELMICFAILURE || ++ iwe->cmd == IWEVCUSTOM || ++ iwe->cmd == IWEVASSOCREQIE || ++ iwe->cmd == IWEVASSOCRESPIE || ++ iwe->cmd == IWEVPMKIDCAND)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ os_memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case SIOCGIWAP: ++ wpa_printf(MSG_DEBUG, "Wireless event: new AP: " ++ MACSTR, ++ MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); ++ if (is_zero_ether_addr( ++ (const u8 *) iwe->u.ap_addr.sa_data) || ++ os_memcmp(iwe->u.ap_addr.sa_data, ++ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == ++ 0) { ++ os_free(drv->assoc_req_ies); ++ drv->assoc_req_ies = NULL; ++ os_free(drv->assoc_resp_ies); ++ drv->assoc_resp_ies = NULL; ++ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, ++ NULL); ++ ++ } else { ++ wpa_driver_wext_event_assoc_ies(drv); ++ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, ++ NULL); ++ } ++ break; ++ case IWEVMICHAELMICFAILURE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVMICHAELMICFAILURE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_michaelmicfailure( ++ drv->ctx, custom, iwe->u.data.length); ++ break; ++ case IWEVCUSTOM: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVCUSTOM length"); ++ return; ++ } ++ buf = dup_binstr(custom, iwe->u.data.length); ++ if (buf == NULL) ++ return; ++ wpa_driver_wext_event_wireless_custom(drv->ctx, buf); ++ os_free(buf); ++ break; ++ case SIOCGIWSCAN: ++ drv->scan_complete_events = 1; ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, ++ drv, drv->ctx); ++ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, ++ NULL); ++ break; ++ case IWEVASSOCREQIE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVASSOCREQIE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_assocreqie( ++ drv, custom, iwe->u.data.length); ++ break; ++ case IWEVASSOCRESPIE: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVASSOCRESPIE length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_assocrespie( ++ drv, custom, iwe->u.data.length); ++ break; ++ case IWEVPMKIDCAND: ++ if (custom + iwe->u.data.length > end) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid " ++ "IWEVPMKIDCAND length"); ++ return; ++ } ++ wpa_driver_wext_event_wireless_pmkidcand( ++ drv, custom, iwe->u.data.length); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++} ++ ++ ++static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, ++ char *buf, size_t len, int del) ++{ ++ union wpa_event_data event; ++ ++ os_memset(&event, 0, sizeof(event)); ++ if (len > sizeof(event.interface_status.ifname)) ++ len = sizeof(event.interface_status.ifname) - 1; ++ os_memcpy(event.interface_status.ifname, buf, len); ++ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : ++ EVENT_INTERFACE_ADDED; ++ ++ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", ++ del ? "DEL" : "NEW", ++ event.interface_status.ifname, ++ del ? "removed" : "added"); ++ ++ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { ++ if (del) { ++ if (drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: if_removed " ++ "already set - ignore event"); ++ return; ++ } ++ drv->if_removed = 1; ++ } else { ++ if (if_nametoindex(drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface %s " ++ "does not exist - ignore " ++ "RTM_NEWLINK", ++ drv->ifname); ++ return; ++ } ++ if (!drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: if_removed " ++ "already cleared - ignore event"); ++ return; ++ } ++ drv->if_removed = 0; ++ } ++ } ++ ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); ++} ++ ++ ++static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, ++ u8 *buf, size_t len) ++{ ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_IFNAME) { ++ if (os_strcmp(((char *) attr) + rta_len, drv->ifname) ++ == 0) ++ return 1; ++ else ++ break; ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++ ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, ++ int ifindex, u8 *buf, size_t len) ++{ ++ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) ++ return 1; ++ ++ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { ++ drv->ifindex = if_nametoindex(drv->ifname); ++ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " ++ "interface"); ++ wpa_driver_wext_finish_drv_init(drv); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, ++ u8 *buf, size_t len) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ char namebuf[IFNAMSIZ]; ++ ++ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { ++ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", ++ ifi->ifi_index); ++ return; ++ } ++ ++ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " ++ "(%s%s%s%s)", ++ drv->operstate, ifi->ifi_flags, ++ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", ++ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", ++ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", ++ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); ++ ++ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface down"); ++ drv->if_disabled = 1; ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); ++ } ++ ++ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { ++ if (if_indextoname(ifi->ifi_index, namebuf) && ++ linux_iface_up(drv->ioctl_sock, drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s is down", ++ namebuf); ++ } else if (if_nametoindex(drv->ifname) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s does not exist", ++ drv->ifname); ++ } else if (drv->if_removed) { ++ wpa_printf(MSG_DEBUG, "WEXT: Ignore interface up " ++ "event since interface %s is marked " ++ "removed", drv->ifname); ++ } else { ++ wpa_printf(MSG_DEBUG, "WEXT: Interface up"); ++ drv->if_disabled = 0; ++ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, ++ NULL); ++ } ++ } ++ ++ /* ++ * Some drivers send the association event before the operup event--in ++ * this case, lifting operstate in wpa_driver_wext_set_operstate() ++ * fails. This will hit us when wpa_supplicant does not need to do ++ * IEEE 802.1X authentication ++ */ ++ if (drv->operstate == 1 && ++ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && ++ !(ifi->ifi_flags & IFF_RUNNING)) ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, ++ -1, IF_OPER_UP); ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ wpa_driver_wext_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } else if (attr->rta_type == IFLA_IFNAME) { ++ wpa_driver_wext_event_link(drv, ++ ((char *) attr) + rta_len, ++ attr->rta_len - rta_len, 0); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, ++ u8 *buf, size_t len) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ int attrlen, rta_len; ++ struct rtattr *attr; ++ ++ attrlen = len; ++ attr = (struct rtattr *) buf; ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_IFNAME) { ++ wpa_driver_wext_event_link(drv, ++ ((char *) attr) + rta_len, ++ attr->rta_len - rta_len, 1); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void wpa_driver_wext_rfkill_blocked(void *ctx) ++{ ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); ++ /* ++ * This may be for any interface; use ifdown event to disable ++ * interface. ++ */ ++} ++ ++ ++static void wpa_driver_wext_rfkill_unblocked(void *ctx) ++{ ++ struct wpa_driver_wext_data *drv = ctx; ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " ++ "after rfkill unblock"); ++ return; ++ } ++ /* rtnetlink ifup handler will report interface as enabled */ ++} ++ ++ ++static void wext_get_phy_name(struct wpa_driver_wext_data *drv) ++{ ++ /* Find phy (radio) to which this interface belongs */ ++ char buf[90], *pos; ++ int f, rv; ++ ++ drv->phyname[0] = '\0'; ++ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", ++ drv->ifname); ++ f = open(buf, O_RDONLY); ++ if (f < 0) { ++ wpa_printf(MSG_DEBUG, "Could not open file %s: %s", ++ buf, strerror(errno)); ++ return; ++ } ++ ++ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); ++ close(f); ++ if (rv < 0) { ++ wpa_printf(MSG_DEBUG, "Could not read file %s: %s", ++ buf, strerror(errno)); ++ return; ++ } ++ ++ drv->phyname[rv] = '\0'; ++ pos = os_strchr(drv->phyname, '\n'); ++ if (pos) ++ *pos = '\0'; ++ wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s", ++ drv->ifname, drv->phyname); ++} ++ ++ ++/** ++ * wpa_driver_wext_init - Initialize WE driver interface ++ * @ctx: context to be used when calling wpa_supplicant functions, ++ * e.g., wpa_supplicant_event() ++ * @ifname: interface name, e.g., wlan0 ++ * Returns: Pointer to private data, %NULL on failure ++ */ ++void * wpa_driver_wext_init(void *ctx, const char *ifname) ++{ ++ struct wpa_driver_wext_data *drv; ++ struct netlink_config *cfg; ++ struct rfkill_config *rcfg; ++ char path[128]; ++ struct stat buf; ++ ++ drv = os_zalloc(sizeof(*drv)); ++ if (drv == NULL) ++ return NULL; ++ drv->ctx = ctx; ++ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); ++ ++ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); ++ if (stat(path, &buf) == 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); ++ drv->cfg80211 = 1; ++ wext_get_phy_name(drv); ++ } ++ ++ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->ioctl_sock < 0) { ++ wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s", ++ strerror(errno)); ++ goto err1; ++ } ++ ++ cfg = os_zalloc(sizeof(*cfg)); ++ if (cfg == NULL) ++ goto err1; ++ cfg->ctx = drv; ++ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; ++ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; ++ drv->netlink = netlink_init(cfg); ++ if (drv->netlink == NULL) { ++ os_free(cfg); ++ goto err2; ++ } ++ ++ rcfg = os_zalloc(sizeof(*rcfg)); ++ if (rcfg == NULL) ++ goto err3; ++ rcfg->ctx = drv; ++ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); ++ rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; ++ rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; ++ drv->rfkill = rfkill_init(rcfg); ++ if (drv->rfkill == NULL) { ++ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); ++ os_free(rcfg); ++ } ++ ++ drv->mlme_sock = -1; ++ ++ if (wpa_driver_wext_finish_drv_init(drv) < 0) ++ goto err3; ++ ++ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); ++ ++ return drv; ++ ++err3: ++ rfkill_deinit(drv->rfkill); ++ netlink_deinit(drv->netlink); ++err2: ++ close(drv->ioctl_sock); ++err1: ++ os_free(drv); ++ return NULL; ++} ++ ++ ++static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) ++{ ++ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); ++} ++ ++ ++static int wext_hostap_ifname(struct wpa_driver_wext_data *drv, ++ const char *ifname) ++{ ++ char buf[200], *res; ++ int type; ++ FILE *f; ++ ++ if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0) ++ return -1; ++ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type", ++ drv->ifname, ifname); ++ ++ f = fopen(buf, "r"); ++ if (!f) ++ return -1; ++ res = fgets(buf, sizeof(buf), f); ++ fclose(f); ++ ++ type = res ? atoi(res) : -1; ++ wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type); ++ ++ if (type == ARPHRD_IEEE80211) { ++ wpa_printf(MSG_DEBUG, ++ "WEXT: Found hostap driver wifi# interface (%s)", ++ ifname); ++ wpa_driver_wext_alternative_ifindex(drv, ifname); ++ return 0; ++ } ++ return -1; ++} ++ ++ ++static int wext_add_hostap(struct wpa_driver_wext_data *drv) ++{ ++ char buf[200]; ++ int n; ++ struct dirent **names; ++ int ret = -1; ++ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname); ++ n = scandir(buf, &names, NULL, alphasort); ++ if (n < 0) ++ return -1; ++ ++ while (n--) { ++ if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0) ++ ret = 0; ++ free(names[n]); ++ } ++ free(names); ++ ++ return ret; ++} ++ ++ ++static void wext_check_hostap(struct wpa_driver_wext_data *drv) ++{ ++ char buf[200], *pos; ++ ssize_t res; ++ ++ /* ++ * Host AP driver may use both wlan# and wifi# interface in wireless ++ * events. Since some of the versions included WE-18 support, let's add ++ * the alternative ifindex also from driver_wext.c for the time being. ++ * This may be removed at some point once it is believed that old ++ * versions of the driver are not in use anymore. However, it looks like ++ * the wifi# interface is still used in the current kernel tree, so it ++ * may not really be possible to remove this before the Host AP driver ++ * gets removed from the kernel. ++ */ ++ ++ /* First, try to see if driver information is available from sysfs */ ++ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", ++ drv->ifname); ++ res = readlink(buf, buf, sizeof(buf) - 1); ++ if (res > 0) { ++ buf[res] = '\0'; ++ pos = strrchr(buf, '/'); ++ if (pos) ++ pos++; ++ else ++ pos = buf; ++ wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos); ++ if (os_strncmp(pos, "hostap", 6) == 0 && ++ wext_add_hostap(drv) == 0) ++ return; ++ } ++ ++ /* Second, use the old design with hardcoded ifname */ ++ if (os_strncmp(drv->ifname, "wlan", 4) == 0) { ++ char ifname2[IFNAMSIZ + 1]; ++ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); ++ os_memcpy(ifname2, "wifi", 4); ++ wpa_driver_wext_alternative_ifindex(drv, ifname2); ++ } ++} ++ ++ ++static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) ++{ ++ int send_rfkill_event = 0; ++ ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { ++ if (rfkill_is_blocked(drv->rfkill)) { ++ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " ++ "interface '%s' due to rfkill", ++ drv->ifname); ++ drv->if_disabled = 1; ++ send_rfkill_event = 1; ++ } else { ++ wpa_printf(MSG_ERROR, "WEXT: Could not set " ++ "interface '%s' UP", drv->ifname); ++ return -1; ++ } ++ } ++ ++ /* ++ * Make sure that the driver does not have any obsolete PMKID entries. ++ */ ++ wpa_driver_wext_flush_pmkid(drv); ++ ++ if (wpa_driver_wext_set_mode(drv, 0) < 0) { ++ wpa_printf(MSG_DEBUG, "Could not configure driver to use " ++ "managed mode"); ++ /* Try to use it anyway */ ++ } ++ ++ wpa_driver_wext_get_range(drv); ++ ++ /* ++ * Unlock the driver's BSSID and force to a random SSID to clear any ++ * previous association the driver might have when the supplicant ++ * starts up. ++ */ ++ wpa_driver_wext_disconnect(drv); ++ ++ drv->ifindex = if_nametoindex(drv->ifname); ++ ++ wext_check_hostap(drv); ++ ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, ++ 1, IF_OPER_DORMANT); ++ ++ if (send_rfkill_event) { ++ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, ++ drv, drv->ctx); ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * wpa_driver_wext_deinit - Deinitialize WE driver interface ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * ++ * Shut down driver interface and processing of driver events. Free ++ * private data buffer if one was allocated in wpa_driver_wext_init(). ++ */ ++void wpa_driver_wext_deinit(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ ++ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); ++ ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); ++ ++ /* ++ * Clear possibly configured driver parameters in order to make it ++ * easier to use the driver after wpa_supplicant has been terminated. ++ */ ++ wpa_driver_wext_disconnect(drv); ++ ++ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); ++ netlink_deinit(drv->netlink); ++ rfkill_deinit(drv->rfkill); ++ ++ if (drv->mlme_sock >= 0) ++ eloop_unregister_read_sock(drv->mlme_sock); ++ ++ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); ++ ++ close(drv->ioctl_sock); ++ if (drv->mlme_sock >= 0) ++ close(drv->mlme_sock); ++ os_free(drv->assoc_req_ies); ++ os_free(drv->assoc_resp_ies); ++ os_free(drv); ++} ++ ++ ++/** ++ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion ++ * @eloop_ctx: Unused ++ * @timeout_ctx: ctx argument given to wpa_driver_wext_init() ++ * ++ * This function can be used as registered timeout when starting a scan to ++ * generate a scan completed event if the driver does not report this. ++ */ ++void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) ++{ ++ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); ++ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); ++} ++ ++ ++/** ++ * wpa_driver_wext_scan - Request the driver to initiate scan ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0, timeout; ++ struct iw_scan_req req; ++ const u8 *ssid = params->ssids[0].ssid; ++ size_t ssid_len = params->ssids[0].ssid_len; ++ ++ if (ssid_len > IW_ESSID_MAX_SIZE) { ++ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", ++ __FUNCTION__, (unsigned long) ssid_len); ++ return -1; ++ } ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ if (ssid && ssid_len) { ++ os_memset(&req, 0, sizeof(req)); ++ req.essid_len = ssid_len; ++ req.bssid.sa_family = ARPHRD_ETHER; ++ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); ++ os_memcpy(req.essid, ssid, ssid_len); ++ iwr.u.data.pointer = (caddr_t) &req; ++ iwr.u.data.length = sizeof(req); ++ iwr.u.data.flags = IW_SCAN_THIS_ESSID; ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ /* Not all drivers generate "scan completed" wireless event, so try to ++ * read results after a timeout. */ ++ timeout = 10; ++ if (drv->scan_complete_events) { ++ /* ++ * The driver seems to deliver SIOCGIWSCAN events to notify ++ * when scan is complete, so use longer timeout to avoid race ++ * conditions with scanning and following association request. ++ */ ++ timeout = 30; ++ } ++ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " ++ "seconds", ret, timeout); ++ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); ++ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, ++ drv->ctx); ++ ++ return ret; ++} ++ ++ ++static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv, ++ size_t *len) ++{ ++ struct iwreq iwr; ++ u8 *res_buf; ++ size_t res_buf_len; ++ ++ res_buf_len = IW_SCAN_MAX_DATA; ++ for (;;) { ++ res_buf = os_malloc(res_buf_len); ++ if (res_buf == NULL) ++ return NULL; ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = res_buf; ++ iwr.u.data.length = res_buf_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) ++ break; ++ ++ if (errno == E2BIG && res_buf_len < 65535) { ++ os_free(res_buf); ++ res_buf = NULL; ++ res_buf_len *= 2; ++ if (res_buf_len > 65535) ++ res_buf_len = 65535; /* 16-bit length field */ ++ wpa_printf(MSG_DEBUG, "Scan results did not fit - " ++ "trying larger buffer (%lu bytes)", ++ (unsigned long) res_buf_len); ++ } else { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s", ++ strerror(errno)); ++ os_free(res_buf); ++ return NULL; ++ } ++ } ++ ++ if (iwr.u.data.length > res_buf_len) { ++ os_free(res_buf); ++ return NULL; ++ } ++ *len = iwr.u.data.length; ++ ++ return res_buf; ++} ++ ++ ++/* ++ * Data structure for collecting WEXT scan results. This is needed to allow ++ * the various methods of reporting IEs to be combined into a single IE buffer. ++ */ ++struct wext_scan_data { ++ struct wpa_scan_res res; ++ u8 *ie; ++ size_t ie_len; ++ u8 ssid[SSID_MAX_LEN]; ++ size_t ssid_len; ++ int maxrate; ++}; ++ ++ ++static void wext_get_scan_mode(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ if (iwe->u.mode == IW_MODE_ADHOC) ++ res->res.caps |= IEEE80211_CAP_IBSS; ++ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) ++ res->res.caps |= IEEE80211_CAP_ESS; ++} ++ ++ ++static void wext_get_scan_ssid(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ int ssid_len = iwe->u.essid.length; ++ if (custom + ssid_len > end) ++ return; ++ if (iwe->u.essid.flags && ++ ssid_len > 0 && ++ ssid_len <= IW_ESSID_MAX_SIZE) { ++ os_memcpy(res->ssid, custom, ssid_len); ++ res->ssid_len = ssid_len; ++ } ++} ++ ++ ++static void wext_get_scan_freq(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ int divi = 1000000, i; ++ ++ if (iwe->u.freq.e == 0) { ++ /* ++ * Some drivers do not report frequency, but a channel. ++ * Try to map this to frequency by assuming they are using ++ * IEEE 802.11b/g. But don't overwrite a previously parsed ++ * frequency if the driver sends both frequency and channel, ++ * since the driver may be sending an A-band channel that we ++ * don't handle here. ++ */ ++ ++ if (res->res.freq) ++ return; ++ ++ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { ++ res->res.freq = 2407 + 5 * iwe->u.freq.m; ++ return; ++ } else if (iwe->u.freq.m == 14) { ++ res->res.freq = 2484; ++ return; ++ } ++ } ++ ++ if (iwe->u.freq.e > 6) { ++ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" ++ MACSTR " m=%d e=%d)", ++ MAC2STR(res->res.bssid), iwe->u.freq.m, ++ iwe->u.freq.e); ++ return; ++ } ++ ++ for (i = 0; i < iwe->u.freq.e; i++) ++ divi /= 10; ++ res->res.freq = iwe->u.freq.m / divi; ++} ++ ++ ++static void wext_get_scan_qual(struct wpa_driver_wext_data *drv, ++ struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ res->res.qual = iwe->u.qual.qual; ++ res->res.noise = iwe->u.qual.noise; ++ res->res.level = iwe->u.qual.level; ++ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) ++ res->res.flags |= WPA_SCAN_QUAL_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) ++ res->res.flags |= WPA_SCAN_LEVEL_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) ++ res->res.flags |= WPA_SCAN_NOISE_INVALID; ++ if (iwe->u.qual.updated & IW_QUAL_DBM) ++ res->res.flags |= WPA_SCAN_LEVEL_DBM; ++ if ((iwe->u.qual.updated & IW_QUAL_DBM) || ++ ((iwe->u.qual.level != 0) && ++ (iwe->u.qual.level > drv->max_level))) { ++ if (iwe->u.qual.level >= 64) ++ res->res.level -= 0x100; ++ if (iwe->u.qual.noise >= 64) ++ res->res.noise -= 0x100; ++ } ++} ++ ++ ++static void wext_get_scan_encode(struct iw_event *iwe, ++ struct wext_scan_data *res) ++{ ++ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) ++ res->res.caps |= IEEE80211_CAP_PRIVACY; ++} ++ ++ ++static void wext_get_scan_rate(struct iw_event *iwe, ++ struct wext_scan_data *res, char *pos, ++ char *end) ++{ ++ int maxrate; ++ char *custom = pos + IW_EV_LCP_LEN; ++ struct iw_param p; ++ size_t clen; ++ ++ clen = iwe->len; ++ if (custom + clen > end) ++ return; ++ maxrate = 0; ++ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { ++ /* Note: may be misaligned, make a local, aligned copy */ ++ os_memcpy(&p, custom, sizeof(struct iw_param)); ++ if (p.value > maxrate) ++ maxrate = p.value; ++ clen -= sizeof(struct iw_param); ++ custom += sizeof(struct iw_param); ++ } ++ ++ /* Convert the maxrate from WE-style (b/s units) to ++ * 802.11 rates (500000 b/s units). ++ */ ++ res->maxrate = maxrate / 500000; ++} ++ ++ ++static void wext_get_scan_iwevgenie(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ char *genie, *gpos, *gend; ++ u8 *tmp; ++ ++ if (iwe->u.data.length == 0) ++ return; ++ ++ gpos = genie = custom; ++ gend = genie + iwe->u.data.length; ++ if (gend > end) { ++ wpa_printf(MSG_INFO, "IWEVGENIE overflow"); ++ return; ++ } ++ ++ tmp = os_realloc(res->ie, res->ie_len + gend - gpos); ++ if (tmp == NULL) ++ return; ++ os_memcpy(tmp + res->ie_len, gpos, gend - gpos); ++ res->ie = tmp; ++ res->ie_len += gend - gpos; ++} ++ ++ ++static void wext_get_scan_custom(struct iw_event *iwe, ++ struct wext_scan_data *res, char *custom, ++ char *end) ++{ ++ size_t clen; ++ u8 *tmp; ++ ++ clen = iwe->u.data.length; ++ if (custom + clen > end) ++ return; ++ ++ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { ++ char *spos; ++ int bytes; ++ spos = custom + 7; ++ bytes = custom + clen - spos; ++ if (bytes & 1 || bytes == 0) ++ return; ++ bytes /= 2; ++ tmp = os_realloc(res->ie, res->ie_len + bytes); ++ if (tmp == NULL) ++ return; ++ res->ie = tmp; ++ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) ++ return; ++ res->ie_len += bytes; ++ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { ++ char *spos; ++ int bytes; ++ spos = custom + 7; ++ bytes = custom + clen - spos; ++ if (bytes & 1 || bytes == 0) ++ return; ++ bytes /= 2; ++ tmp = os_realloc(res->ie, res->ie_len + bytes); ++ if (tmp == NULL) ++ return; ++ res->ie = tmp; ++ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) ++ return; ++ res->ie_len += bytes; ++ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { ++ char *spos; ++ int bytes; ++ u8 bin[8]; ++ spos = custom + 4; ++ bytes = custom + clen - spos; ++ if (bytes != 16) { ++ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); ++ return; ++ } ++ bytes /= 2; ++ if (hexstr2bin(spos, bin, bytes) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); ++ return; ++ } ++ res->res.tsf += WPA_GET_BE64(bin); ++ } ++} ++ ++ ++static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd) ++{ ++ return drv->we_version_compiled > 18 && ++ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || ++ cmd == IWEVGENIE || cmd == IWEVCUSTOM); ++} ++ ++ ++static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, ++ struct wext_scan_data *data) ++{ ++ struct wpa_scan_res **tmp; ++ struct wpa_scan_res *r; ++ size_t extra_len; ++ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; ++ ++ /* Figure out whether we need to fake any IEs */ ++ pos = data->ie; ++ end = pos + data->ie_len; ++ while (pos && pos + 1 < end) { ++ if (pos + 2 + pos[1] > end) ++ break; ++ if (pos[0] == WLAN_EID_SSID) ++ ssid_ie = pos; ++ else if (pos[0] == WLAN_EID_SUPP_RATES) ++ rate_ie = pos; ++ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) ++ rate_ie = pos; ++ pos += 2 + pos[1]; ++ } ++ ++ extra_len = 0; ++ if (ssid_ie == NULL) ++ extra_len += 2 + data->ssid_len; ++ if (rate_ie == NULL && data->maxrate) ++ extra_len += 3; ++ ++ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); ++ if (r == NULL) ++ return; ++ os_memcpy(r, &data->res, sizeof(*r)); ++ r->ie_len = extra_len + data->ie_len; ++ pos = (u8 *) (r + 1); ++ if (ssid_ie == NULL) { ++ /* ++ * Generate a fake SSID IE since the driver did not report ++ * a full IE list. ++ */ ++ *pos++ = WLAN_EID_SSID; ++ *pos++ = data->ssid_len; ++ os_memcpy(pos, data->ssid, data->ssid_len); ++ pos += data->ssid_len; ++ } ++ if (rate_ie == NULL && data->maxrate) { ++ /* ++ * Generate a fake Supported Rates IE since the driver did not ++ * report a full IE list. ++ */ ++ *pos++ = WLAN_EID_SUPP_RATES; ++ *pos++ = 1; ++ *pos++ = data->maxrate; ++ } ++ if (data->ie) ++ os_memcpy(pos, data->ie, data->ie_len); ++ ++ tmp = os_realloc_array(res->res, res->num + 1, ++ sizeof(struct wpa_scan_res *)); ++ if (tmp == NULL) { ++ os_free(r); ++ return; ++ } ++ tmp[res->num++] = r; ++ res->res = tmp; ++} ++ ++ ++/** ++ * wpa_driver_wext_get_scan_results - Fetch the latest scan results ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * Returns: Scan results on success, -1 on failure ++ */ ++struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ size_t len; ++ int first; ++ u8 *res_buf; ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom; ++ struct wpa_scan_results *res; ++ struct wext_scan_data data; ++ ++ res_buf = wpa_driver_wext_giwscan(drv, &len); ++ if (res_buf == NULL) ++ return NULL; ++ ++ first = 1; ++ ++ res = os_zalloc(sizeof(*res)); ++ if (res == NULL) { ++ os_free(res_buf); ++ return NULL; ++ } ++ ++ pos = (char *) res_buf; ++ end = (char *) res_buf + len; ++ os_memset(&data, 0, sizeof(data)); ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ break; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (wext_19_iw_point(drv, iwe->cmd)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ os_memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case SIOCGIWAP: ++ if (!first) ++ wpa_driver_wext_add_scan_entry(res, &data); ++ first = 0; ++ os_free(data.ie); ++ os_memset(&data, 0, sizeof(data)); ++ os_memcpy(data.res.bssid, ++ iwe->u.ap_addr.sa_data, ETH_ALEN); ++ break; ++ case SIOCGIWMODE: ++ wext_get_scan_mode(iwe, &data); ++ break; ++ case SIOCGIWESSID: ++ wext_get_scan_ssid(iwe, &data, custom, end); ++ break; ++ case SIOCGIWFREQ: ++ wext_get_scan_freq(iwe, &data); ++ break; ++ case IWEVQUAL: ++ wext_get_scan_qual(drv, iwe, &data); ++ break; ++ case SIOCGIWENCODE: ++ wext_get_scan_encode(iwe, &data); ++ break; ++ case SIOCGIWRATE: ++ wext_get_scan_rate(iwe, &data, pos, end); ++ break; ++ case IWEVGENIE: ++ wext_get_scan_iwevgenie(iwe, &data, custom, end); ++ break; ++ case IWEVCUSTOM: ++ wext_get_scan_custom(iwe, &data, custom, end); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++ os_free(res_buf); ++ res_buf = NULL; ++ if (!first) ++ wpa_driver_wext_add_scan_entry(res, &data); ++ os_free(data.ie); ++ ++ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", ++ (unsigned long) len, (unsigned long) res->num); ++ ++ return res; ++} ++ ++ ++static int wpa_driver_wext_get_range(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iw_range *range; ++ struct iwreq iwr; ++ int minlen; ++ size_t buflen; ++ ++ /* ++ * Use larger buffer than struct iw_range in order to allow the ++ * structure to grow in the future. ++ */ ++ buflen = sizeof(struct iw_range) + 500; ++ range = os_zalloc(buflen); ++ if (range == NULL) ++ return -1; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) range; ++ iwr.u.data.length = buflen; ++ ++ minlen = ((char *) &range->enc_capa) - (char *) range + ++ sizeof(range->enc_capa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s", ++ strerror(errno)); ++ os_free(range); ++ return -1; ++ } else if (iwr.u.data.length >= minlen && ++ range->we_version_compiled >= 18) { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " ++ "WE(source)=%d enc_capa=0x%x", ++ range->we_version_compiled, ++ range->we_version_source, ++ range->enc_capa); ++ drv->has_capability = 1; ++ drv->we_version_compiled = range->we_version_compiled; ++ if (range->enc_capa & IW_ENC_CAPA_WPA) { ++ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; ++ } ++ if (range->enc_capa & IW_ENC_CAPA_WPA2) { ++ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | ++ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; ++ } ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | ++ WPA_DRIVER_CAPA_ENC_WEP104; ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP128; ++ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; ++ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) ++ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; ++ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) ++ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; ++ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | ++ WPA_DRIVER_AUTH_SHARED | ++ WPA_DRIVER_AUTH_LEAP; ++ drv->capa.max_scan_ssids = 1; ++ ++ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " ++ "flags 0x%llx", ++ drv->capa.key_mgmt, drv->capa.enc, ++ (unsigned long long) drv->capa.flags); ++ } else { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " ++ "assuming WPA is not supported"); ++ } ++ ++ drv->max_level = range->max_qual.level; ++ ++ os_free(range); ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, ++ const u8 *psk) ++{ ++ struct iw_encode_ext *ext; ++ struct iwreq iwr; ++ int ret; ++ ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ++ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) ++ return 0; ++ ++ if (!psk) ++ return 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ ++ ext = os_zalloc(sizeof(*ext) + PMK_LEN); ++ if (ext == NULL) ++ return -1; ++ ++ iwr.u.encoding.pointer = (caddr_t) ext; ++ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN; ++ ext->key_len = PMK_LEN; ++ os_memcpy(&ext->key, psk, ext->key_len); ++ ext->alg = IW_ENCODE_ALG_PMK; ++ ++ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr); ++ if (ret < 0) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s", ++ strerror(errno)); ++ os_free(ext); ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, ++ const u8 *addr, int key_idx, ++ int set_tx, const u8 *seq, ++ size_t seq_len, ++ const u8 *key, size_t key_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ struct iw_encode_ext *ext; ++ ++ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { ++ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", ++ __FUNCTION__, (unsigned long) seq_len); ++ return -1; ++ } ++ ++ ext = os_zalloc(sizeof(*ext) + key_len); ++ if (ext == NULL) ++ return -1; ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ if (alg == WPA_ALG_NONE) ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ iwr.u.encoding.pointer = (caddr_t) ext; ++ iwr.u.encoding.length = sizeof(*ext) + key_len; ++ ++ if (addr == NULL || is_broadcast_ether_addr(addr)) ++ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; ++ if (set_tx) ++ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; ++ ++ ext->addr.sa_family = ARPHRD_ETHER; ++ if (addr) ++ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN); ++ else ++ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN); ++ if (key && key_len) { ++ os_memcpy(ext + 1, key, key_len); ++ ext->key_len = key_len; ++ } ++ switch (alg) { ++ case WPA_ALG_NONE: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ break; ++ case WPA_ALG_WEP: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ break; ++ case WPA_ALG_TKIP: ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ break; ++ case WPA_ALG_CCMP: ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ break; ++ case WPA_ALG_PMK: ++ ext->alg = IW_ENCODE_ALG_PMK; ++ break; ++#ifdef CONFIG_IEEE80211W ++ case WPA_ALG_IGTK: ++ ext->alg = IW_ENCODE_ALG_AES_CMAC; ++ break; ++#endif /* CONFIG_IEEE80211W */ ++ default: ++ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", ++ __FUNCTION__, alg); ++ os_free(ext); ++ return -1; ++ } ++ ++ if (seq && seq_len) { ++ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; ++ os_memcpy(ext->rx_seq, seq, seq_len); ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { ++ ret = errno == EOPNOTSUPP ? -2 : -1; ++ if (errno == ENODEV) { ++ /* ++ * ndiswrapper seems to be returning incorrect error ++ * code.. */ ++ ret = -2; ++ } ++ ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s", ++ strerror(errno)); ++ } ++ ++ os_free(ext); ++ return ret; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_key - Configure encryption key ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @priv: Private driver interface data ++ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, ++ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. ++ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for ++ * broadcast/default keys ++ * @key_idx: key index (0..3), usually 0 for unicast keys ++ * @set_tx: Configure this key as the default Tx key (only used when ++ * driver does not support separate unicast/individual key ++ * @seq: Sequence number/packet number, seq_len octets, the next ++ * packet number to be used for in replay protection; configured ++ * for Rx keys (in most cases, this is only used with broadcast ++ * keys and set to zero for unicast keys) ++ * @seq_len: Length of the seq, depends on the algorithm: ++ * TKIP: 6 octets, CCMP: 6 octets ++ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, ++ * 8-byte Rx Mic Key ++ * @key_len: Length of the key buffer in octets (WEP: 5 or 13, ++ * TKIP: 32, CCMP: 16) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This function uses SIOCSIWENCODEEXT by default, but tries to use ++ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. ++ */ ++int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, ++ const u8 *addr, int key_idx, ++ int set_tx, const u8 *seq, size_t seq_len, ++ const u8 *key, size_t key_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " ++ "key_len=%lu", ++ __FUNCTION__, alg, key_idx, set_tx, ++ (unsigned long) seq_len, (unsigned long) key_len); ++ ++ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, ++ seq, seq_len, key, key_len); ++ if (ret == 0) ++ return 0; ++ ++ if (ret == -2 && ++ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) { ++ wpa_printf(MSG_DEBUG, "Driver did not support " ++ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE"); ++ ret = 0; ++ } else { ++ wpa_printf(MSG_DEBUG, "Driver did not support " ++ "SIOCSIWENCODEEXT"); ++ return ret; ++ } ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ if (alg == WPA_ALG_NONE) ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ iwr.u.encoding.pointer = (caddr_t) key; ++ iwr.u.encoding.length = key_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ if (set_tx && alg != WPA_ALG_NONE) { ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.encoding.flags = key_idx + 1; ++ iwr.u.encoding.flags |= IW_ENCODE_TEMP; ++ iwr.u.encoding.pointer = (caddr_t) NULL; ++ iwr.u.encoding.length = 0; ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, ++ "ioctl[SIOCSIWENCODE] (set_tx): %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ } ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_countermeasures(void *priv, ++ int enabled) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ return wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_TKIP_COUNTERMEASURES, ++ enabled); ++} ++ ++ ++static int wpa_driver_wext_set_drop_unencrypted(void *priv, ++ int enabled) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ drv->use_crypt = enabled; ++ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, ++ enabled); ++} ++ ++ ++static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv, ++ const u8 *addr, int cmd, int reason_code) ++{ ++ struct iwreq iwr; ++ struct iw_mlme mlme; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ os_memset(&mlme, 0, sizeof(mlme)); ++ mlme.cmd = cmd; ++ mlme.reason_code = reason_code; ++ mlme.addr.sa_family = ARPHRD_ETHER; ++ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); ++ iwr.u.data.pointer = (caddr_t) &mlme; ++ iwr.u.data.length = sizeof(mlme); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) ++{ ++ struct iwreq iwr; ++ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; ++ u8 ssid[SSID_MAX_LEN]; ++ int i; ++ ++ /* ++ * Only force-disconnect when the card is in infrastructure mode, ++ * otherwise the driver might interpret the cleared BSSID and random ++ * SSID as an attempt to create a new ad-hoc network. ++ */ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", ++ strerror(errno)); ++ iwr.u.mode = IW_MODE_INFRA; ++ } ++ ++ if (iwr.u.mode == IW_MODE_INFRA) { ++ /* Clear the BSSID selection */ ++ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID " ++ "selection on disconnect"); ++ } ++ ++ if (drv->cfg80211) { ++ /* ++ * cfg80211 supports SIOCSIWMLME commands, so there is ++ * no need for the random SSID hack, but clear the ++ * SSID. ++ */ ++ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " ++ "SSID on disconnect"); ++ } ++ return; ++ } ++ ++ /* ++ * Set a random SSID to make sure the driver will not be trying ++ * to associate with something even if it does not understand ++ * SIOCSIWMLME commands (or tries to associate automatically ++ * after deauth/disassoc). ++ */ ++ for (i = 0; i < SSID_MAX_LEN; i++) ++ ssid[i] = rand() & 0xFF; ++ if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) { ++ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " ++ "SSID to disconnect"); ++ } ++ } ++} ++ ++ ++static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr, ++ int reason_code) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int ret; ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); ++ wpa_driver_wext_disconnect(drv); ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, ++ size_t ie_len) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) ie; ++ iwr.u.data.length = ie_len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++int wpa_driver_wext_cipher2wext(int cipher) ++{ ++ switch (cipher) { ++ case WPA_CIPHER_NONE: ++ return IW_AUTH_CIPHER_NONE; ++ case WPA_CIPHER_WEP40: ++ return IW_AUTH_CIPHER_WEP40; ++ case WPA_CIPHER_TKIP: ++ return IW_AUTH_CIPHER_TKIP; ++ case WPA_CIPHER_CCMP: ++ return IW_AUTH_CIPHER_CCMP; ++ case WPA_CIPHER_WEP104: ++ return IW_AUTH_CIPHER_WEP104; ++ default: ++ return 0; ++ } ++} ++ ++ ++int wpa_driver_wext_keymgmt2wext(int keymgmt) ++{ ++ switch (keymgmt) { ++ case WPA_KEY_MGMT_IEEE8021X: ++ case WPA_KEY_MGMT_IEEE8021X_NO_WPA: ++ return IW_AUTH_KEY_MGMT_802_1X; ++ case WPA_KEY_MGMT_PSK: ++ return IW_AUTH_KEY_MGMT_PSK; ++ default: ++ return 0; ++ } ++} ++ ++ ++static int ++wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, ++ struct wpa_driver_associate_params *params) ++{ ++ struct iwreq iwr; ++ int ret = 0; ++ ++ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " ++ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ /* Just changing mode, not actual keys */ ++ iwr.u.encoding.flags = 0; ++ iwr.u.encoding.pointer = (caddr_t) NULL; ++ iwr.u.encoding.length = 0; ++ ++ /* ++ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two ++ * different things. Here they are used to indicate Open System vs. ++ * Shared Key authentication algorithm. However, some drivers may use ++ * them to select between open/restricted WEP encrypted (open = allow ++ * both unencrypted and encrypted frames; restricted = only allow ++ * encrypted frames). ++ */ ++ ++ if (!drv->use_crypt) { ++ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; ++ } else { ++ if (params->auth_alg & WPA_AUTH_ALG_OPEN) ++ iwr.u.encoding.flags |= IW_ENCODE_OPEN; ++ if (params->auth_alg & WPA_AUTH_ALG_SHARED) ++ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; ++ } ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++int wpa_driver_wext_associate(void *priv, ++ struct wpa_driver_associate_params *params) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int ret = 0; ++ int allow_unencrypted_eapol; ++ int value; ++ ++ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); ++ ++ if (drv->cfg80211) { ++ /* ++ * Stop cfg80211 from trying to associate before we are done ++ * with all parameters. ++ */ ++ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { ++ wpa_printf(MSG_DEBUG, ++ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)"); ++ /* continue anyway */ ++ } ++ } ++ ++ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) ++ < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_mode(drv, params->mode) < 0) ++ ret = -1; ++ ++ /* ++ * If the driver did not support SIOCSIWAUTH, fallback to ++ * SIOCSIWENCODE here. ++ */ ++ if (drv->auth_alg_fallback && ++ wpa_driver_wext_auth_alg_fallback(drv, params) < 0) ++ ret = -1; ++ ++ if (!params->bssid && ++ wpa_driver_wext_set_bssid(drv, NULL) < 0) ++ ret = -1; ++ ++ /* TODO: should consider getting wpa version and cipher/key_mgmt suites ++ * from configuration, not from here, where only the selected suite is ++ * available */ ++ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) ++ < 0) ++ ret = -1; ++ if (params->wpa_proto & WPA_PROTO_RSN) ++ value = IW_AUTH_WPA_VERSION_WPA2; ++ else if (params->wpa_proto & WPA_PROTO_WPA) ++ value = IW_AUTH_WPA_VERSION_WPA; ++ else ++ value = IW_AUTH_WPA_VERSION_DISABLED; ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_WPA_VERSION, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_cipher2wext(params->pairwise_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_CIPHER_PAIRWISE, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_cipher2wext(params->group_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_CIPHER_GROUP, value) < 0) ++ ret = -1; ++ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_KEY_MGMT, value) < 0) ++ ret = -1; ++ value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE || ++ params->pairwise_suite != WPA_CIPHER_NONE || ++ params->group_suite != WPA_CIPHER_NONE || ++ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)); ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_PRIVACY_INVOKED, value) < 0) ++ ret = -1; ++ ++ /* Allow unencrypted EAPOL messages even if pairwise keys are set when ++ * not using WPA. IEEE 802.1X specifies that these frames are not ++ * encrypted, but WPA encrypts them when pairwise keys are in use. */ ++ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || ++ params->key_mgmt_suite == WPA_KEY_MGMT_PSK) ++ allow_unencrypted_eapol = 0; ++ else ++ allow_unencrypted_eapol = 1; ++ ++ if (wpa_driver_wext_set_psk(drv, params->psk) < 0) ++ ret = -1; ++ if (wpa_driver_wext_set_auth_param(drv, ++ IW_AUTH_RX_UNENCRYPTED_EAPOL, ++ allow_unencrypted_eapol) < 0) ++ ret = -1; ++#ifdef CONFIG_IEEE80211W ++ switch (params->mgmt_frame_protection) { ++ case NO_MGMT_FRAME_PROTECTION: ++ value = IW_AUTH_MFP_DISABLED; ++ break; ++ case MGMT_FRAME_PROTECTION_OPTIONAL: ++ value = IW_AUTH_MFP_OPTIONAL; ++ break; ++ case MGMT_FRAME_PROTECTION_REQUIRED: ++ value = IW_AUTH_MFP_REQUIRED; ++ break; ++ }; ++ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) ++ ret = -1; ++#endif /* CONFIG_IEEE80211W */ ++ if (params->freq.freq && ++ wpa_driver_wext_set_freq(drv, params->freq.freq) < 0) ++ ret = -1; ++ if (!drv->cfg80211 && ++ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) ++ ret = -1; ++ if (params->bssid && ++ wpa_driver_wext_set_bssid(drv, params->bssid) < 0) ++ ret = -1; ++ if (drv->cfg80211 && ++ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) ++ ret = -1; ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int algs = 0, res; ++ ++ if (auth_alg & WPA_AUTH_ALG_OPEN) ++ algs |= IW_AUTH_ALG_OPEN_SYSTEM; ++ if (auth_alg & WPA_AUTH_ALG_SHARED) ++ algs |= IW_AUTH_ALG_SHARED_KEY; ++ if (auth_alg & WPA_AUTH_ALG_LEAP) ++ algs |= IW_AUTH_ALG_LEAP; ++ if (algs == 0) { ++ /* at least one algorithm should be set */ ++ algs = IW_AUTH_ALG_OPEN_SYSTEM; ++ } ++ ++ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, ++ algs); ++ drv->auth_alg_fallback = res == -2; ++ return res; ++} ++ ++ ++/** ++ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE ++ * @priv: Pointer to private wext data from wpa_driver_wext_init() ++ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS ++ * Returns: 0 on success, -1 on failure ++ */ ++int wpa_driver_wext_set_mode(void *priv, int mode) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iwreq iwr; ++ int ret = -1; ++ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.mode = new_mode; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) { ++ ret = 0; ++ goto done; ++ } ++ ++ if (errno != EBUSY) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", ++ strerror(errno)); ++ goto done; ++ } ++ ++ /* mac80211 doesn't allow mode changes while the device is up, so if ++ * the device isn't in the mode we're about to change to, take device ++ * down, try to set the mode again, and bring it back up. ++ */ ++ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s", ++ strerror(errno)); ++ goto done; ++ } ++ ++ if (iwr.u.mode == new_mode) { ++ ret = 0; ++ goto done; ++ } ++ ++ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { ++ /* Try to set the mode again while the interface is down */ ++ iwr.u.mode = new_mode; ++ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s", ++ strerror(errno)); ++ else ++ ret = 0; ++ ++ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); ++ } ++ ++done: ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv, ++ u32 cmd, const u8 *bssid, const u8 *pmkid) ++{ ++ struct iwreq iwr; ++ struct iw_pmksa pmksa; ++ int ret = 0; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ os_memset(&pmksa, 0, sizeof(pmksa)); ++ pmksa.cmd = cmd; ++ pmksa.bssid.sa_family = ARPHRD_ETHER; ++ if (bssid) ++ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); ++ if (pmkid) ++ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); ++ iwr.u.data.pointer = (caddr_t) &pmksa; ++ iwr.u.data.length = sizeof(pmksa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { ++ if (errno != EOPNOTSUPP) ++ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s", ++ strerror(errno)); ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++ ++static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid, ++ const u8 *pmkid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); ++} ++ ++ ++static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid, ++ const u8 *pmkid) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); ++} ++ ++ ++static int wpa_driver_wext_flush_pmkid(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); ++} ++ ++ ++int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ if (!drv->has_capability) ++ return -1; ++ os_memcpy(capa, &drv->capa, sizeof(*capa)); ++ return 0; ++} ++ ++ ++int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, ++ const char *ifname) ++{ ++ if (ifname == NULL) { ++ drv->ifindex2 = -1; ++ return 0; ++ } ++ ++ drv->ifindex2 = if_nametoindex(ifname); ++ if (drv->ifindex2 <= 0) ++ return -1; ++ ++ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for " ++ "wireless events", drv->ifindex2, ifname); ++ ++ return 0; ++} ++ ++ ++int wpa_driver_wext_set_operstate(void *priv, int state) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ ++ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", ++ __func__, drv->operstate, state, state ? "UP" : "DORMANT"); ++ drv->operstate = state; ++ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, ++ state ? IF_OPER_UP : IF_OPER_DORMANT); ++} ++ ++ ++int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) ++{ ++ return drv->we_version_compiled; ++} ++ ++ ++static const char * wext_get_radio_name(void *priv) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ return drv->phyname; ++} ++ ++ ++static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ struct iw_statistics stats; ++ struct iwreq iwr; ++ ++ os_memset(si, 0, sizeof(*si)); ++ si->current_signal = -9999; ++ si->current_noise = 9999; ++ si->chanwidth = CHAN_WIDTH_UNKNOWN; ++ ++ os_memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) &stats; ++ iwr.u.data.length = sizeof(stats); ++ iwr.u.data.flags = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { ++ wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s", ++ strerror(errno)); ++ return -1; ++ } ++ ++ si->current_signal = stats.qual.level - ++ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); ++ si->current_noise = stats.qual.noise - ++ ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); ++ return 0; ++} ++ ++ ++static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen) ++{ ++ struct wpa_driver_wext_data *drv = priv; ++ int res; ++ char *pos, *end; ++ unsigned char addr[ETH_ALEN]; ++ ++ pos = buf; ++ end = buf + buflen; ++ ++ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr)) ++ return -1; ++ ++ res = os_snprintf(pos, end - pos, ++ "ifindex=%d\n" ++ "ifname=%s\n" ++ "addr=" MACSTR "\n", ++ drv->ifindex, ++ drv->ifname, ++ MAC2STR(addr)); ++ if (os_snprintf_error(end - pos, res)) ++ return pos - buf; ++ pos += res; ++ ++ return pos - buf; ++} ++ ++const struct wpa_driver_ops wpa_driver_wext_ops = { ++ .name = "wext", ++ .desc = "Linux wireless extensions (generic)", ++ .get_bssid = wpa_driver_wext_get_bssid, ++ .get_ssid = wpa_driver_wext_get_ssid, ++ .set_key = wpa_driver_wext_set_key, ++ .set_countermeasures = wpa_driver_wext_set_countermeasures, ++ .scan2 = wpa_driver_wext_scan, ++ .get_scan_results2 = wpa_driver_wext_get_scan_results, ++ .deauthenticate = wpa_driver_wext_deauthenticate, ++ .associate = wpa_driver_wext_associate, ++ .init = wpa_driver_wext_init, ++ .deinit = wpa_driver_wext_deinit, ++ .add_pmkid = wpa_driver_wext_add_pmkid, ++ .remove_pmkid = wpa_driver_wext_remove_pmkid, ++ .flush_pmkid = wpa_driver_wext_flush_pmkid, ++ .get_capa = wpa_driver_wext_get_capa, ++ .set_operstate = wpa_driver_wext_set_operstate, ++ .get_radio_name = wext_get_radio_name, ++ .signal_poll = wpa_driver_wext_signal_poll, ++ .status = wpa_driver_wext_status, ++}; +diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c +index a98af9a..d7d9c5b 100644 +--- a/src/drivers/drivers.c ++++ b/src/drivers/drivers.c +@@ -45,6 +45,9 @@ extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ + #ifdef CONFIG_DRIVER_NONE + extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ + #endif /* CONFIG_DRIVER_NONE */ ++#ifdef CONFIG_DRIVER_RTW ++extern struct wpa_driver_ops wpa_driver_rtw_ops; /* driver_rtw.c */ ++#endif /* CONFIG_DRIVER_RTW */ + + + const struct wpa_driver_ops *const wpa_drivers[] = +@@ -82,5 +85,8 @@ const struct wpa_driver_ops *const wpa_drivers[] = + #ifdef CONFIG_DRIVER_NONE + &wpa_driver_none_ops, + #endif /* CONFIG_DRIVER_NONE */ ++#ifdef CONFIG_DRIVER_RTW ++ &wpa_driver_rtw_ops, ++#endif /* CONFIG_DRIVER_RTW */ + NULL + }; +diff --git a/src/drivers/drivers.c.orig b/src/drivers/drivers.c.orig +new file mode 100644 +index 0000000..a98af9a +--- /dev/null ++++ b/src/drivers/drivers.c.orig +@@ -0,0 +1,86 @@ ++/* ++ * Driver interface list ++ * Copyright (c) 2004-2005, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "utils/includes.h" ++#include "utils/common.h" ++#include "driver.h" ++ ++#ifdef CONFIG_DRIVER_WEXT ++extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ ++#endif /* CONFIG_DRIVER_WEXT */ ++#ifdef CONFIG_DRIVER_NL80211 ++extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ ++#endif /* CONFIG_DRIVER_NL80211 */ ++#ifdef CONFIG_DRIVER_HOSTAP ++extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ ++#endif /* CONFIG_DRIVER_HOSTAP */ ++#ifdef CONFIG_DRIVER_BSD ++extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ ++#endif /* CONFIG_DRIVER_BSD */ ++#ifdef CONFIG_DRIVER_OPENBSD ++extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */ ++#endif /* CONFIG_DRIVER_OPENBSD */ ++#ifdef CONFIG_DRIVER_NDIS ++extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ ++#endif /* CONFIG_DRIVER_NDIS */ ++#ifdef CONFIG_DRIVER_WIRED ++extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ ++#endif /* CONFIG_DRIVER_WIRED */ ++#ifdef CONFIG_DRIVER_MACSEC_QCA ++ /* driver_macsec_qca.c */ ++extern struct wpa_driver_ops wpa_driver_macsec_qca_ops; ++#endif /* CONFIG_DRIVER_MACSEC_QCA */ ++#ifdef CONFIG_DRIVER_ROBOSWITCH ++/* driver_roboswitch.c */ ++extern struct wpa_driver_ops wpa_driver_roboswitch_ops; ++#endif /* CONFIG_DRIVER_ROBOSWITCH */ ++#ifdef CONFIG_DRIVER_ATHEROS ++extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ ++#endif /* CONFIG_DRIVER_ATHEROS */ ++#ifdef CONFIG_DRIVER_NONE ++extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ ++#endif /* CONFIG_DRIVER_NONE */ ++ ++ ++const struct wpa_driver_ops *const wpa_drivers[] = ++{ ++#ifdef CONFIG_DRIVER_NL80211 ++ &wpa_driver_nl80211_ops, ++#endif /* CONFIG_DRIVER_NL80211 */ ++#ifdef CONFIG_DRIVER_WEXT ++ &wpa_driver_wext_ops, ++#endif /* CONFIG_DRIVER_WEXT */ ++#ifdef CONFIG_DRIVER_HOSTAP ++ &wpa_driver_hostap_ops, ++#endif /* CONFIG_DRIVER_HOSTAP */ ++#ifdef CONFIG_DRIVER_BSD ++ &wpa_driver_bsd_ops, ++#endif /* CONFIG_DRIVER_BSD */ ++#ifdef CONFIG_DRIVER_OPENBSD ++ &wpa_driver_openbsd_ops, ++#endif /* CONFIG_DRIVER_OPENBSD */ ++#ifdef CONFIG_DRIVER_NDIS ++ &wpa_driver_ndis_ops, ++#endif /* CONFIG_DRIVER_NDIS */ ++#ifdef CONFIG_DRIVER_WIRED ++ &wpa_driver_wired_ops, ++#endif /* CONFIG_DRIVER_WIRED */ ++#ifdef CONFIG_DRIVER_MACSEC_QCA ++ &wpa_driver_macsec_qca_ops, ++#endif /* CONFIG_DRIVER_MACSEC_QCA */ ++#ifdef CONFIG_DRIVER_ROBOSWITCH ++ &wpa_driver_roboswitch_ops, ++#endif /* CONFIG_DRIVER_ROBOSWITCH */ ++#ifdef CONFIG_DRIVER_ATHEROS ++ &wpa_driver_atheros_ops, ++#endif /* CONFIG_DRIVER_ATHEROS */ ++#ifdef CONFIG_DRIVER_NONE ++ &wpa_driver_none_ops, ++#endif /* CONFIG_DRIVER_NONE */ ++ NULL ++}; +diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak +index 3dd43c7..3e44fcb 100644 +--- a/src/drivers/drivers.mak ++++ b/src/drivers/drivers.mak +@@ -74,6 +74,10 @@ DRV_CFLAGS += -DCONFIG_DRIVER_BSD + DRV_OBJS += ../src/drivers/driver_bsd.o + CONFIG_L2_FREEBSD=y + CONFIG_DNET_PCAP=y ++ifdef CONFIG_SUPPORT_RTW_DRIVER ++DRV_CFLAGS += -DCONFIG_SUPPORT_RTW_DRIVER -DCONFIG_DRIVER_RTL_DFS ++NEED_AP_MLME=y ++endif + endif + + ifdef CONFIG_DRIVER_OPENBSD +@@ -84,6 +88,17 @@ DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD + DRV_OBJS += ../src/drivers/driver_openbsd.o + endif + ++ifdef CONFIG_DRIVER_RTW ++#CFLAGS += -DCONFIG_DRIVER_RTL ++#OBJS += driver_rtl.o ++DRV_AP_CFLAGS += -DCONFIG_DRIVER_RTW -DCONFIG_DRIVER_RTL_DFS ++DRV_AP_OBJS += ../src/drivers/driver_rtw.o ++CONFIG_L2_PACKET=linux ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++NEED_AP_MLME=y ++endif ++ + ifdef CONFIG_DRIVER_NONE + DRV_CFLAGS += -DCONFIG_DRIVER_NONE + DRV_OBJS += ../src/drivers/driver_none.o +diff --git a/src/drivers/drivers.mak.orig b/src/drivers/drivers.mak.orig +new file mode 100644 +index 0000000..3dd43c7 +--- /dev/null ++++ b/src/drivers/drivers.mak.orig +@@ -0,0 +1,200 @@ ++##### CLEAR VARS ++ ++DRV_CFLAGS = ++DRV_WPA_CFLAGS = ++DRV_AP_CFLAGS = ++DRV_OBJS = ++DRV_WPA_OBJS = ++DRV_AP_OBJS = ++DRV_LIBS = ++DRV_WPA_LIBS = ++DRV_AP_LIBS = ++ ++##### COMMON DRIVERS ++ ++ifdef CONFIG_DRIVER_WIRED ++DRV_CFLAGS += -DCONFIG_DRIVER_WIRED ++DRV_OBJS += ../src/drivers/driver_wired.o ++endif ++ ++ifdef CONFIG_DRIVER_MACSEC_QCA ++DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA ++DRV_OBJS += ../src/drivers/driver_macsec_qca.o ++endif ++ ++ifdef CONFIG_DRIVER_NL80211 ++DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 ++DRV_OBJS += ../src/drivers/driver_nl80211.o ++DRV_OBJS += ../src/drivers/driver_nl80211_capa.o ++DRV_OBJS += ../src/drivers/driver_nl80211_event.o ++DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o ++DRV_OBJS += ../src/drivers/driver_nl80211_scan.o ++DRV_OBJS += ../src/utils/radiotap.o ++NEED_SME=y ++NEED_AP_MLME=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++NEED_RFKILL=y ++ ++ifdef CONFIG_LIBNL32 ++ DRV_LIBS += -lnl-3 ++ DRV_LIBS += -lnl-genl-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ ifdef LIBNL_INC ++ DRV_CFLAGS += -I$(LIBNL_INC) ++ else ++ PKG_CONFIG ?= pkg-config ++ DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0) ++ endif ++ifdef CONFIG_LIBNL3_ROUTE ++ DRV_LIBS += -lnl-route-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE ++endif ++else ++ ifdef CONFIG_LIBNL_TINY ++ DRV_LIBS += -lnl-tiny ++ else ++ ifndef CONFIG_OSX ++ DRV_LIBS += -lnl ++ endif ++ endif ++ ++ ifdef CONFIG_LIBNL20 ++ DRV_LIBS += -lnl-genl ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ endif ++endif ++endif ++ ++ifdef CONFIG_DRIVER_BSD ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=freebsd ++endif ++DRV_CFLAGS += -DCONFIG_DRIVER_BSD ++DRV_OBJS += ../src/drivers/driver_bsd.o ++CONFIG_L2_FREEBSD=y ++CONFIG_DNET_PCAP=y ++endif ++ ++ifdef CONFIG_DRIVER_OPENBSD ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=freebsd ++endif ++DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD ++DRV_OBJS += ../src/drivers/driver_openbsd.o ++endif ++ ++ifdef CONFIG_DRIVER_NONE ++DRV_CFLAGS += -DCONFIG_DRIVER_NONE ++DRV_OBJS += ../src/drivers/driver_none.o ++endif ++ ++##### PURE AP DRIVERS ++ ++ifdef CONFIG_DRIVER_HOSTAP ++DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP ++DRV_AP_OBJS += ../src/drivers/driver_hostap.o ++CONFIG_WIRELESS_EXTENSION=y ++NEED_AP_MLME=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++endif ++ ++ifdef CONFIG_DRIVER_ATHEROS ++DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS ++DRV_AP_OBJS += ../src/drivers/driver_atheros.o ++CONFIG_L2_PACKET=linux ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++ifdef ATH_GCM_SUPPORT ++CFLAGS += -DATH_GCM_SUPPORT ++endif ++endif ++ ++##### PURE CLIENT DRIVERS ++ ++ifdef CONFIG_DRIVER_WEXT ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT ++CONFIG_WIRELESS_EXTENSION=y ++NEED_NETLINK=y ++NEED_LINUX_IOCTL=y ++NEED_RFKILL=y ++endif ++ ++ifdef CONFIG_DRIVER_NDIS ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS ++DRV_WPA_OBJS += ../src/drivers/driver_ndis.o ++ifdef CONFIG_NDIS_EVENTS_INTEGRATED ++DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o ++endif ++ifndef CONFIG_L2_PACKET ++CONFIG_L2_PACKET=pcap ++endif ++CONFIG_WINPCAP=y ++ifdef CONFIG_USE_NDISUIO ++DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO ++endif ++endif ++ ++ifdef CONFIG_DRIVER_ROBOSWITCH ++DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH ++DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o ++endif ++ ++ifdef CONFIG_WIRELESS_EXTENSION ++DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION ++DRV_WPA_OBJS += ../src/drivers/driver_wext.o ++NEED_RFKILL=y ++endif ++ ++ifdef NEED_NETLINK ++DRV_OBJS += ../src/drivers/netlink.o ++endif ++ ++ifdef NEED_LINUX_IOCTL ++DRV_OBJS += ../src/drivers/linux_ioctl.o ++endif ++ ++ifdef NEED_RFKILL ++DRV_OBJS += ../src/drivers/rfkill.o ++endif ++ ++ifdef CONFIG_VLAN_NETLINK ++ifdef CONFIG_FULL_DYNAMIC_VLAN ++ifdef CONFIG_LIBNL32 ++ DRV_LIBS += -lnl-3 ++ DRV_LIBS += -lnl-genl-3 ++ DRV_LIBS += -lnl-route-3 ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++else ++ ifdef CONFIG_LIBNL_TINY ++ DRV_LIBS += -lnl-tiny ++ else ++ DRV_LIBS += -lnl ++ endif ++ ++ ifdef CONFIG_LIBNL20 ++ DRV_LIBS += -lnl-genl ++ DRV_LIBS += -lnl-route ++ DRV_CFLAGS += -DCONFIG_LIBNL20 ++ endif ++endif ++endif ++endif ++ ++##### COMMON VARS ++DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) ++DRV_WPA_CFLAGS += $(DRV_CFLAGS) ++DRV_AP_CFLAGS += $(DRV_CFLAGS) ++ ++DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS) ++DRV_WPA_LIBS += $(DRV_LIBS) ++DRV_AP_LIBS += $(DRV_LIBS) ++ ++DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS) ++DRV_WPA_OBJS += $(DRV_OBJS) ++DRV_AP_OBJS += $(DRV_OBJS) ++ ++DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS) ++DRV_WPA_LDFLAGS += $(DRV_LDFLAGS) ++DRV_AP_LDFLAGS += $(DRV_LDFLAGS) +diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c +index 7ac99c7..1f7697c 100644 +--- a/src/eap_peer/eap_wsc.c ++++ b/src/eap_peer/eap_wsc.c +@@ -569,8 +569,13 @@ send_msg: + r = eap_wsc_build_msg(data, ret, id); + if (data->state == FAIL && ret->methodState == METHOD_DONE) { + /* Use reduced client timeout for WPS to avoid long wait */ ++#if 0 /* Aries add, 2012/06/12, extend timeout for AP IOT */ ++ if (sm->ClientTimeout > 4) ++ sm->ClientTimeout = 4; ++#else + if (sm->ClientTimeout > 2) + sm->ClientTimeout = 2; ++#endif + } + return r; + } +diff --git a/src/eap_peer/eap_wsc.c.orig b/src/eap_peer/eap_wsc.c.orig +new file mode 100644 +index 0000000..7ac99c7 +--- /dev/null ++++ b/src/eap_peer/eap_wsc.c.orig +@@ -0,0 +1,598 @@ ++/* ++ * EAP-WSC peer for Wi-Fi Protected Setup ++ * Copyright (c) 2007-2009, 2012, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "uuid.h" ++#include "eap_i.h" ++#include "eap_common/eap_wsc_common.h" ++#include "wps/wps.h" ++#include "wps/wps_defs.h" ++ ++ ++struct eap_wsc_data { ++ enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; ++ int registrar; ++ struct wpabuf *in_buf; ++ struct wpabuf *out_buf; ++ enum wsc_op_code in_op_code, out_op_code; ++ size_t out_used; ++ size_t fragment_size; ++ struct wps_data *wps; ++ struct wps_context *wps_ctx; ++}; ++ ++ ++static const char * eap_wsc_state_txt(int state) ++{ ++ switch (state) { ++ case WAIT_START: ++ return "WAIT_START"; ++ case MESG: ++ return "MESG"; ++ case FRAG_ACK: ++ return "FRAG_ACK"; ++ case WAIT_FRAG_ACK: ++ return "WAIT_FRAG_ACK"; ++ case DONE: ++ return "DONE"; ++ case FAIL: ++ return "FAIL"; ++ default: ++ return "?"; ++ } ++} ++ ++ ++static void eap_wsc_state(struct eap_wsc_data *data, int state) ++{ ++ wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", ++ eap_wsc_state_txt(data->state), ++ eap_wsc_state_txt(state)); ++ data->state = state; ++} ++ ++ ++static int eap_wsc_new_ap_settings(struct wps_credential *cred, ++ const char *params) ++{ ++ const char *pos, *end; ++ size_t len; ++ ++ os_memset(cred, 0, sizeof(*cred)); ++ ++ pos = os_strstr(params, "new_ssid="); ++ if (pos == NULL) ++ return 0; ++ pos += 9; ++ end = os_strchr(pos, ' '); ++ if (end == NULL) ++ len = os_strlen(pos); ++ else ++ len = end - pos; ++ if ((len & 1) || len > 2 * sizeof(cred->ssid) || ++ hexstr2bin(pos, cred->ssid, len / 2)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid"); ++ return -1; ++ } ++ cred->ssid_len = len / 2; ++ ++ pos = os_strstr(params, "new_auth="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth"); ++ return -1; ++ } ++ if (os_strncmp(pos + 9, "OPEN", 4) == 0) ++ cred->auth_type = WPS_AUTH_OPEN; ++ else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) ++ cred->auth_type = WPS_AUTH_WPAPSK; ++ else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) ++ cred->auth_type = WPS_AUTH_WPA2PSK; ++ else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth"); ++ return -1; ++ } ++ ++ pos = os_strstr(params, "new_encr="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr"); ++ return -1; ++ } ++ if (os_strncmp(pos + 9, "NONE", 4) == 0) ++ cred->encr_type = WPS_ENCR_NONE; ++#ifdef CONFIG_TESTING_OPTIONS ++ else if (os_strncmp(pos + 9, "WEP", 3) == 0) ++ cred->encr_type = WPS_ENCR_WEP; ++#endif /* CONFIG_TESTING_OPTIONS */ ++ else if (os_strncmp(pos + 9, "TKIP", 4) == 0) ++ cred->encr_type = WPS_ENCR_TKIP; ++ else if (os_strncmp(pos + 9, "CCMP", 4) == 0) ++ cred->encr_type = WPS_ENCR_AES; ++ else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr"); ++ return -1; ++ } ++ ++ pos = os_strstr(params, "new_key="); ++ if (pos == NULL) ++ return 0; ++ pos += 8; ++ end = os_strchr(pos, ' '); ++ if (end == NULL) ++ len = os_strlen(pos); ++ else ++ len = end - pos; ++ if ((len & 1) || len > 2 * sizeof(cred->key) || ++ hexstr2bin(pos, cred->key, len / 2)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key"); ++ return -1; ++ } ++ cred->key_len = len / 2; ++ ++ return 1; ++} ++ ++ ++static void * eap_wsc_init(struct eap_sm *sm) ++{ ++ struct eap_wsc_data *data; ++ const u8 *identity; ++ size_t identity_len; ++ int registrar; ++ struct wps_config cfg; ++ const char *pos, *end; ++ const char *phase1; ++ struct wps_context *wps; ++ struct wps_credential new_ap_settings; ++ int res; ++ int nfc = 0; ++ u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN]; ++ ++ wps = sm->wps; ++ if (wps == NULL) { ++ wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); ++ return NULL; ++ } ++ ++ identity = eap_get_config_identity(sm, &identity_len); ++ ++ if (identity && identity_len == WSC_ID_REGISTRAR_LEN && ++ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) ++ registrar = 1; /* Supplicant is Registrar */ ++ else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && ++ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) ++ registrar = 0; /* Supplicant is Enrollee */ ++ else { ++ wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", ++ identity, identity_len); ++ return NULL; ++ } ++ ++ data = os_zalloc(sizeof(*data)); ++ if (data == NULL) ++ return NULL; ++ data->state = registrar ? MESG : WAIT_START; ++ data->registrar = registrar; ++ data->wps_ctx = wps; ++ ++ os_memset(&cfg, 0, sizeof(cfg)); ++ cfg.wps = wps; ++ cfg.registrar = registrar; ++ ++ phase1 = eap_get_config_phase1(sm); ++ if (phase1 == NULL) { ++ wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " ++ "set"); ++ os_free(data); ++ return NULL; ++ } ++ ++ pos = os_strstr(phase1, "pin="); ++ if (pos) { ++ pos += 4; ++ cfg.pin = (const u8 *) pos; ++ while (*pos != '\0' && *pos != ' ') ++ pos++; ++ cfg.pin_len = pos - (const char *) cfg.pin; ++ if (cfg.pin_len == 6 && ++ os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) { ++ cfg.pin = NULL; ++ cfg.pin_len = 0; ++ nfc = 1; ++ } ++ } else { ++ pos = os_strstr(phase1, "pbc=1"); ++ if (pos) ++ cfg.pbc = 1; ++ } ++ ++ pos = os_strstr(phase1, "dev_pw_id="); ++ if (pos) { ++ u16 id = atoi(pos + 10); ++ if (id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ nfc = 1; ++ if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ cfg.dev_pw_id = id; ++ } ++ ++ if (cfg.pin == NULL && !cfg.pbc && !nfc) { ++ wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " ++ "configuration data"); ++ os_free(data); ++ return NULL; ++ } ++ ++ pos = os_strstr(phase1, " pkhash="); ++ if (pos) { ++ size_t len; ++ pos += 8; ++ end = os_strchr(pos, ' '); ++ if (end) ++ len = end - pos; ++ else ++ len = os_strlen(pos); ++ if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN || ++ hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) { ++ wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash"); ++ os_free(data); ++ return NULL; ++ } ++ cfg.peer_pubkey_hash = pkhash; ++ } ++ ++ res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); ++ if (res < 0) { ++ os_free(data); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP " ++ "settings"); ++ return NULL; ++ } ++ if (res == 1) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " ++ "WPS"); ++ cfg.new_ap_settings = &new_ap_settings; ++ } ++ ++ data->wps = wps_init(&cfg); ++ if (data->wps == NULL) { ++ os_free(data); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed"); ++ return NULL; ++ } ++ res = eap_get_config_fragment_size(sm); ++ if (res > 0) ++ data->fragment_size = res; ++ else ++ data->fragment_size = WSC_FRAGMENT_SIZE; ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", ++ (unsigned int) data->fragment_size); ++ ++ if (registrar && cfg.pin) { ++ wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, ++ cfg.pin, cfg.pin_len, 0); ++ } ++ ++ /* Use reduced client timeout for WPS to avoid long wait */ ++ if (sm->ClientTimeout > 30) ++ sm->ClientTimeout = 30; ++ ++ return data; ++} ++ ++ ++static void eap_wsc_deinit(struct eap_sm *sm, void *priv) ++{ ++ struct eap_wsc_data *data = priv; ++ wpabuf_free(data->in_buf); ++ wpabuf_free(data->out_buf); ++ wps_deinit(data->wps); ++ os_free(data->wps_ctx->network_key); ++ data->wps_ctx->network_key = NULL; ++ os_free(data); ++} ++ ++ ++static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, ++ struct eap_method_ret *ret, u8 id) ++{ ++ struct wpabuf *resp; ++ u8 flags; ++ size_t send_len, plen; ++ ++ ret->ignore = FALSE; ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); ++ ret->allowNotifications = TRUE; ++ ++ flags = 0; ++ send_len = wpabuf_len(data->out_buf) - data->out_used; ++ if (2 + send_len > data->fragment_size) { ++ send_len = data->fragment_size - 2; ++ flags |= WSC_FLAGS_MF; ++ if (data->out_used == 0) { ++ flags |= WSC_FLAGS_LF; ++ send_len -= 2; ++ } ++ } ++ plen = 2 + send_len; ++ if (flags & WSC_FLAGS_LF) ++ plen += 2; ++ resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, ++ EAP_CODE_RESPONSE, id); ++ if (resp == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ ++ wpabuf_put_u8(resp, flags); /* Flags */ ++ if (flags & WSC_FLAGS_LF) ++ wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); ++ ++ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, ++ send_len); ++ data->out_used += send_len; ++ ++ ret->methodState = METHOD_MAY_CONT; ++ ret->decision = DECISION_FAIL; ++ ++ if (data->out_used == wpabuf_len(data->out_buf)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " ++ "(message sent completely)", ++ (unsigned long) send_len); ++ wpabuf_free(data->out_buf); ++ data->out_buf = NULL; ++ data->out_used = 0; ++ if ((data->state == FAIL && data->out_op_code == WSC_ACK) || ++ data->out_op_code == WSC_NACK || ++ data->out_op_code == WSC_Done) { ++ eap_wsc_state(data, FAIL); ++ ret->methodState = METHOD_DONE; ++ } else ++ eap_wsc_state(data, MESG); ++ } else { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " ++ "(%lu more to send)", (unsigned long) send_len, ++ (unsigned long) wpabuf_len(data->out_buf) - ++ data->out_used); ++ eap_wsc_state(data, WAIT_FRAG_ACK); ++ } ++ ++ return resp; ++} ++ ++ ++static int eap_wsc_process_cont(struct eap_wsc_data *data, ++ const u8 *buf, size_t len, u8 op_code) ++{ ++ /* Process continuation of a pending message */ ++ if (op_code != data->in_op_code) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " ++ "fragment (expected %d)", ++ op_code, data->in_op_code); ++ return -1; ++ } ++ ++ if (len > wpabuf_tailroom(data->in_buf)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); ++ eap_wsc_state(data, FAIL); ++ return -1; ++ } ++ ++ wpabuf_put_data(data->in_buf, buf, len); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " ++ "for %lu bytes more", (unsigned long) len, ++ (unsigned long) wpabuf_tailroom(data->in_buf)); ++ ++ return 0; ++} ++ ++ ++static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, ++ struct eap_method_ret *ret, ++ u8 id, u8 flags, u8 op_code, ++ u16 message_length, ++ const u8 *buf, size_t len) ++{ ++ /* Process a fragment that is not the last one of the message */ ++ if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " ++ "fragmented packet"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->in_buf == NULL) { ++ /* First fragment of the message */ ++ data->in_buf = wpabuf_alloc(message_length); ++ if (data->in_buf == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " ++ "message"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ data->in_op_code = op_code; ++ wpabuf_put_data(data->in_buf, buf, len); ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " ++ "fragment, waiting for %lu bytes more", ++ (unsigned long) len, ++ (unsigned long) wpabuf_tailroom(data->in_buf)); ++ } ++ ++ return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); ++} ++ ++ ++static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, ++ struct eap_method_ret *ret, ++ const struct wpabuf *reqData) ++{ ++ struct eap_wsc_data *data = priv; ++ const u8 *start, *pos, *end; ++ size_t len; ++ u8 op_code, flags, id; ++ u16 message_length = 0; ++ enum wps_process_res res; ++ struct wpabuf tmpbuf; ++ struct wpabuf *r; ++ ++ pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, ++ &len); ++ if (pos == NULL || len < 2) { ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ id = eap_get_id(reqData); ++ ++ start = pos; ++ end = start + len; ++ ++ op_code = *pos++; ++ flags = *pos++; ++ if (flags & WSC_FLAGS_LF) { ++ if (end - pos < 2) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ message_length = WPA_GET_BE16(pos); ++ pos += 2; ++ ++ if (message_length < end - pos || message_length > 50000) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " ++ "Length"); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ } ++ ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " ++ "Flags 0x%x Message Length %d", ++ op_code, flags, message_length); ++ ++ if (data->state == WAIT_FRAG_ACK) { ++ if (op_code != WSC_FRAG_ACK) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " ++ "in WAIT_FRAG_ACK state", op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); ++ eap_wsc_state(data, MESG); ++ return eap_wsc_build_msg(data, ret, id); ++ } ++ ++ if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && ++ op_code != WSC_Done && op_code != WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", ++ op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->state == WAIT_START) { ++ if (op_code != WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " ++ "in WAIT_START state", op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); ++ eap_wsc_state(data, MESG); ++ /* Start message has empty payload, skip processing */ ++ goto send_msg; ++ } else if (op_code == WSC_Start) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", ++ op_code); ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (data->in_buf && ++ eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { ++ ret->ignore = TRUE; ++ return NULL; ++ } ++ ++ if (flags & WSC_FLAGS_MF) { ++ return eap_wsc_process_fragment(data, ret, id, flags, op_code, ++ message_length, pos, ++ end - pos); ++ } ++ ++ if (data->in_buf == NULL) { ++ /* Wrap unfragmented messages as wpabuf without extra copy */ ++ wpabuf_set(&tmpbuf, pos, end - pos); ++ data->in_buf = &tmpbuf; ++ } ++ ++ res = wps_process_msg(data->wps, op_code, data->in_buf); ++ switch (res) { ++ case WPS_DONE: ++ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " ++ "successfully - wait for EAP failure"); ++ eap_wsc_state(data, FAIL); ++ break; ++ case WPS_CONTINUE: ++ eap_wsc_state(data, MESG); ++ break; ++ case WPS_FAILURE: ++ case WPS_PENDING: ++ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); ++ eap_wsc_state(data, FAIL); ++ break; ++ } ++ ++ if (data->in_buf != &tmpbuf) ++ wpabuf_free(data->in_buf); ++ data->in_buf = NULL; ++ ++send_msg: ++ if (data->out_buf == NULL) { ++ data->out_buf = wps_get_msg(data->wps, &data->out_op_code); ++ if (data->out_buf == NULL) { ++ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " ++ "message from WPS"); ++ eap_wsc_state(data, FAIL); ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_FAIL; ++ return NULL; ++ } ++ data->out_used = 0; ++ } ++ ++ eap_wsc_state(data, MESG); ++ r = eap_wsc_build_msg(data, ret, id); ++ if (data->state == FAIL && ret->methodState == METHOD_DONE) { ++ /* Use reduced client timeout for WPS to avoid long wait */ ++ if (sm->ClientTimeout > 2) ++ sm->ClientTimeout = 2; ++ } ++ return r; ++} ++ ++ ++int eap_peer_wsc_register(void) ++{ ++ struct eap_method *eap; ++ int ret; ++ ++ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, ++ EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, ++ "WSC"); ++ if (eap == NULL) ++ return -1; ++ ++ eap->init = eap_wsc_init; ++ eap->deinit = eap_wsc_deinit; ++ eap->process = eap_wsc_process; ++ ++ ret = eap_peer_method_register(eap); ++ if (ret) ++ eap_peer_method_free(eap); ++ return ret; ++} +diff --git a/src/wps/wps.c b/src/wps/wps.c +index fbaf85a..10a82e1 100644 +--- a/src/wps/wps.c ++++ b/src/wps/wps.c +@@ -321,11 +321,15 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, + if (wps_parse_msg(msg, &attr) < 0) + return 0; + ++ return is_selected_pin_registrar(&attr); ++// Marked by Albert 2011/11/17 ++// Some APs won't carry the AuthorizedMACs in the probe response. ++// So, skip this check will speed up the process to find the current AP out for WPS handshake. ++/* + if (!attr.version2 && ver1_compat) { + /* + * Version 1.0 AP - AuthorizedMACs not used, so revert back to + * old mechanism of using SelectedRegistrar. +- */ + return is_selected_pin_registrar(&attr); + } + +@@ -342,6 +346,7 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, + } + + return 0; ++*/ + } + + +diff --git a/src/wps/wps.c.orig b/src/wps/wps.c.orig +new file mode 100644 +index 0000000..fbaf85a +--- /dev/null ++++ b/src/wps/wps.c.orig +@@ -0,0 +1,662 @@ ++/* ++ * Wi-Fi Protected Setup ++ * Copyright (c) 2007-2009, Jouni Malinen ++ * ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "crypto/dh_group5.h" ++#include "common/ieee802_11_defs.h" ++#include "wps_i.h" ++#include "wps_dev_attr.h" ++ ++ ++#ifdef CONFIG_WPS_TESTING ++int wps_version_number = 0x20; ++int wps_testing_dummy_cred = 0; ++int wps_corrupt_pkhash = 0; ++#endif /* CONFIG_WPS_TESTING */ ++ ++ ++/** ++ * wps_init - Initialize WPS Registration protocol data ++ * @cfg: WPS configuration ++ * Returns: Pointer to allocated data or %NULL on failure ++ * ++ * This function is used to initialize WPS data for a registration protocol ++ * instance (i.e., each run of registration protocol as a Registrar of ++ * Enrollee. The caller is responsible for freeing this data after the ++ * registration run has been completed by calling wps_deinit(). ++ */ ++struct wps_data * wps_init(const struct wps_config *cfg) ++{ ++ struct wps_data *data = os_zalloc(sizeof(*data)); ++ if (data == NULL) ++ return NULL; ++ data->wps = cfg->wps; ++ data->registrar = cfg->registrar; ++ if (cfg->registrar) { ++ os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); ++ } else { ++ os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); ++ os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); ++ } ++ if (cfg->pin) { ++ data->dev_pw_id = cfg->dev_pw_id; ++ data->dev_password = os_malloc(cfg->pin_len); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); ++ data->dev_password_len = cfg->pin_len; ++ wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password", ++ data->dev_password, data->dev_password_len); ++ } ++ ++#ifdef CONFIG_WPS_NFC ++ if (cfg->pin == NULL && ++ cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) ++ data->dev_pw_id = cfg->dev_pw_id; ++ ++ if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { ++ /* Keep AP PIN as alternative Device Password */ ++ data->alt_dev_pw_id = data->dev_pw_id; ++ data->alt_dev_password = data->dev_password; ++ data->alt_dev_password_len = data->dev_password_len; ++ ++ data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; ++ data->dev_password = ++ os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw)); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->dev_password, ++ wpabuf_head(cfg->wps->ap_nfc_dev_pw), ++ wpabuf_len(cfg->wps->ap_nfc_dev_pw)); ++ data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); ++ wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password", ++ data->dev_password, data->dev_password_len); ++ } ++#endif /* CONFIG_WPS_NFC */ ++ ++ data->pbc = cfg->pbc; ++ if (cfg->pbc) { ++ /* Use special PIN '00000000' for PBC */ ++ data->dev_pw_id = DEV_PW_PUSHBUTTON; ++ bin_clear_free(data->dev_password, data->dev_password_len); ++ data->dev_password = (u8 *) os_strdup("00000000"); ++ if (data->dev_password == NULL) { ++ os_free(data); ++ return NULL; ++ } ++ data->dev_password_len = 8; ++ } ++ ++ data->state = data->registrar ? RECV_M1 : SEND_M1; ++ ++ if (cfg->assoc_wps_ie) { ++ struct wps_parse_attr attr; ++ wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", ++ cfg->assoc_wps_ie); ++ if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { ++ wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " ++ "from (Re)AssocReq"); ++ } else if (attr.request_type == NULL) { ++ wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " ++ "in (Re)AssocReq WPS IE"); ++ } else { ++ wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " ++ "in (Re)AssocReq WPS IE): %d", ++ *attr.request_type); ++ data->request_type = *attr.request_type; ++ } ++ } ++ ++ if (cfg->new_ap_settings) { ++ data->new_ap_settings = ++ os_malloc(sizeof(*data->new_ap_settings)); ++ if (data->new_ap_settings == NULL) { ++ bin_clear_free(data->dev_password, ++ data->dev_password_len); ++ os_free(data); ++ return NULL; ++ } ++ os_memcpy(data->new_ap_settings, cfg->new_ap_settings, ++ sizeof(*data->new_ap_settings)); ++ } ++ ++ if (cfg->peer_addr) ++ os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); ++ if (cfg->p2p_dev_addr) ++ os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); ++ ++ data->use_psk_key = cfg->use_psk_key; ++ data->pbc_in_m1 = cfg->pbc_in_m1; ++ ++ if (cfg->peer_pubkey_hash) { ++ os_memcpy(data->peer_pubkey_hash, cfg->peer_pubkey_hash, ++ WPS_OOB_PUBKEY_HASH_LEN); ++ data->peer_pubkey_hash_set = 1; ++ } ++ ++ return data; ++} ++ ++ ++/** ++ * wps_deinit - Deinitialize WPS Registration protocol data ++ * @data: WPS Registration protocol data from wps_init() ++ */ ++void wps_deinit(struct wps_data *data) ++{ ++#ifdef CONFIG_WPS_NFC ++ if (data->registrar && data->nfc_pw_token) ++ wps_registrar_remove_nfc_pw_token(data->wps->registrar, ++ data->nfc_pw_token); ++#endif /* CONFIG_WPS_NFC */ ++ ++ if (data->wps_pin_revealed) { ++ wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " ++ "negotiation failed"); ++ if (data->registrar) ++ wps_registrar_invalidate_pin(data->wps->registrar, ++ data->uuid_e); ++ } else if (data->registrar) ++ wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); ++ ++ wpabuf_free(data->dh_privkey); ++ wpabuf_free(data->dh_pubkey_e); ++ wpabuf_free(data->dh_pubkey_r); ++ wpabuf_free(data->last_msg); ++ bin_clear_free(data->dev_password, data->dev_password_len); ++ bin_clear_free(data->alt_dev_password, data->alt_dev_password_len); ++ bin_clear_free(data->new_psk, data->new_psk_len); ++ wps_device_data_free(&data->peer_dev); ++ bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); ++ dh5_free(data->dh_ctx); ++ os_free(data); ++} ++ ++ ++/** ++ * wps_process_msg - Process a WPS message ++ * @wps: WPS Registration protocol data from wps_init() ++ * @op_code: Message OP Code ++ * @msg: Message data ++ * Returns: Processing result ++ * ++ * This function is used to process WPS messages with OP Codes WSC_ACK, ++ * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is ++ * responsible for reassembling the messages before calling this function. ++ * Response to this message is built by calling wps_get_msg(). ++ */ ++enum wps_process_res wps_process_msg(struct wps_data *wps, ++ enum wsc_op_code op_code, ++ const struct wpabuf *msg) ++{ ++ if (wps->registrar) ++ return wps_registrar_process_msg(wps, op_code, msg); ++ else ++ return wps_enrollee_process_msg(wps, op_code, msg); ++} ++ ++ ++/** ++ * wps_get_msg - Build a WPS message ++ * @wps: WPS Registration protocol data from wps_init() ++ * @op_code: Buffer for returning message OP Code ++ * Returns: The generated WPS message or %NULL on failure ++ * ++ * This function is used to build a response to a message processed by calling ++ * wps_process_msg(). The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) ++{ ++ if (wps->registrar) ++ return wps_registrar_get_msg(wps, op_code); ++ else ++ return wps_enrollee_get_msg(wps, op_code); ++} ++ ++ ++/** ++ * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if PBC Registrar is active, 0 if not ++ */ ++int wps_is_selected_pbc_registrar(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ /* ++ * In theory, this could also verify that attr.sel_reg_config_methods ++ * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations ++ * do not set Selected Registrar Config Methods attribute properly, so ++ * it is safer to just use Device Password ID here. ++ */ ++ ++ if (wps_parse_msg(msg, &attr) < 0 || ++ !attr.selected_registrar || *attr.selected_registrar == 0 || ++ !attr.dev_password_id || ++ WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) ++ return 0; ++ ++#ifdef CONFIG_WPS_STRICT ++ if (!attr.sel_reg_config_methods || ++ !(WPA_GET_BE16(attr.sel_reg_config_methods) & ++ WPS_CONFIG_PUSHBUTTON)) ++ return 0; ++#endif /* CONFIG_WPS_STRICT */ ++ ++ return 1; ++} ++ ++ ++static int is_selected_pin_registrar(struct wps_parse_attr *attr) ++{ ++ /* ++ * In theory, this could also verify that attr.sel_reg_config_methods ++ * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, ++ * but some deployed AP implementations do not set Selected Registrar ++ * Config Methods attribute properly, so it is safer to just use ++ * Device Password ID here. ++ */ ++ ++ if (!attr->selected_registrar || *attr->selected_registrar == 0) ++ return 0; ++ ++ if (attr->dev_password_id != NULL && ++ WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) ++ return 0; ++ ++#ifdef CONFIG_WPS_STRICT ++ if (!attr->sel_reg_config_methods || ++ !(WPA_GET_BE16(attr->sel_reg_config_methods) & ++ (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) ++ return 0; ++#endif /* CONFIG_WPS_STRICT */ ++ ++ return 1; ++} ++ ++ ++/** ++ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if PIN Registrar is active, 0 if not ++ */ ++int wps_is_selected_pin_registrar(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ ++ return is_selected_pin_registrar(&attr); ++} ++ ++ ++/** ++ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * @addr: MAC address to search for ++ * @ver1_compat: Whether to use version 1 compatibility mode ++ * Returns: 2 if the specified address is explicit authorized, 1 if address is ++ * authorized (broadcast), 0 if not ++ */ ++int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, ++ int ver1_compat) ++{ ++ struct wps_parse_attr attr; ++ unsigned int i; ++ const u8 *pos; ++ const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ ++ if (!attr.version2 && ver1_compat) { ++ /* ++ * Version 1.0 AP - AuthorizedMACs not used, so revert back to ++ * old mechanism of using SelectedRegistrar. ++ */ ++ return is_selected_pin_registrar(&attr); ++ } ++ ++ if (!attr.authorized_macs) ++ return 0; ++ ++ pos = attr.authorized_macs; ++ for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { ++ if (os_memcmp(pos, addr, ETH_ALEN) == 0) ++ return 2; ++ if (os_memcmp(pos, bcast, ETH_ALEN) == 0) ++ return 1; ++ pos += ETH_ALEN; ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * wps_ap_priority_compar - Prioritize WPS IE from two APs ++ * @wps_a: WPS IE contents from Beacon or Probe Response frame ++ * @wps_b: WPS IE contents from Beacon or Probe Response frame ++ * Returns: 1 if wps_b is considered more likely selection for WPS ++ * provisioning, -1 if wps_a is considered more like, or 0 if no preference ++ */ ++int wps_ap_priority_compar(const struct wpabuf *wps_a, ++ const struct wpabuf *wps_b) ++{ ++ struct wps_parse_attr attr; ++ int sel_a, sel_b; ++ ++ if (wps_a == NULL || wps_parse_msg(wps_a, &attr) < 0) ++ return 1; ++ sel_a = attr.selected_registrar && *attr.selected_registrar != 0; ++ ++ if (wps_b == NULL || wps_parse_msg(wps_b, &attr) < 0) ++ return -1; ++ sel_b = attr.selected_registrar && *attr.selected_registrar != 0; ++ ++ if (sel_a && !sel_b) ++ return -1; ++ if (!sel_a && sel_b) ++ return 1; ++ ++ return 0; ++} ++ ++ ++/** ++ * wps_get_uuid_e - Get UUID-E from WPS IE ++ * @msg: WPS IE contents from Beacon or Probe Response frame ++ * Returns: Pointer to UUID-E or %NULL if not included ++ * ++ * The returned pointer is to the msg contents and it remains valid only as ++ * long as the msg buffer is valid. ++ */ ++const u8 * wps_get_uuid_e(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (wps_parse_msg(msg, &attr) < 0) ++ return NULL; ++ return attr.uuid_e; ++} ++ ++ ++/** ++ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 ++ */ ++int wps_is_20(const struct wpabuf *msg) ++{ ++ struct wps_parse_attr attr; ++ ++ if (msg == NULL || wps_parse_msg(msg, &attr) < 0) ++ return 0; ++ return attr.version2 != NULL; ++} ++ ++ ++/** ++ * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request ++ * @req_type: Value for Request Type attribute ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) ++{ ++ struct wpabuf *ie; ++ u8 *len; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " ++ "Request"); ++ ie = wpabuf_alloc(100); ++ if (ie == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); ++ len = wpabuf_put(ie, 1); ++ wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); ++ ++ if (wps_build_version(ie) || ++ wps_build_req_type(ie, req_type) || ++ wps_build_wfa_ext(ie, 0, NULL, 0)) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ *len = wpabuf_len(ie) - 2; ++ ++ return ie; ++} ++ ++ ++/** ++ * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_assoc_resp_ie(void) ++{ ++ struct wpabuf *ie; ++ u8 *len; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " ++ "Response"); ++ ie = wpabuf_alloc(100); ++ if (ie == NULL) ++ return NULL; ++ ++ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); ++ len = wpabuf_put(ie, 1); ++ wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); ++ ++ if (wps_build_version(ie) || ++ wps_build_resp_type(ie, WPS_RESP_AP) || ++ wps_build_wfa_ext(ie, 0, NULL, 0)) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ *len = wpabuf_len(ie) - 2; ++ ++ return ie; ++} ++ ++ ++/** ++ * wps_build_probe_req_ie - Build WPS IE for Probe Request ++ * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for ++ * most other use cases) ++ * @dev: Device attributes ++ * @uuid: Own UUID ++ * @req_type: Value for Request Type attribute ++ * @num_req_dev_types: Number of requested device types ++ * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or ++ * %NULL if none ++ * Returns: WPS IE or %NULL on failure ++ * ++ * The caller is responsible for freeing the buffer. ++ */ ++struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, ++ const u8 *uuid, ++ enum wps_request_type req_type, ++ unsigned int num_req_dev_types, ++ const u8 *req_dev_types) ++{ ++ struct wpabuf *ie; ++ ++ wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); ++ ++ ie = wpabuf_alloc(500); ++ if (ie == NULL) ++ return NULL; ++ ++ if (wps_build_version(ie) || ++ wps_build_req_type(ie, req_type) || ++ wps_build_config_methods(ie, dev->config_methods) || ++ wps_build_uuid_e(ie, uuid) || ++ wps_build_primary_dev_type(dev, ie) || ++ wps_build_rf_bands(dev, ie, 0) || ++ wps_build_assoc_state(NULL, ie) || ++ wps_build_config_error(ie, WPS_CFG_NO_ERROR) || ++ wps_build_dev_password_id(ie, pw_id) || ++ wps_build_manufacturer(dev, ie) || ++ wps_build_model_name(dev, ie) || ++ wps_build_model_number(dev, ie) || ++ wps_build_dev_name(dev, ie) || ++ wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || ++ wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) ++ || ++ wps_build_secondary_dev_type(dev, ie) ++ ) { ++ wpabuf_free(ie); ++ return NULL; ++ } ++ ++ return wps_ie_encapsulate(ie); ++} ++ ++ ++void wps_free_pending_msgs(struct upnp_pending_message *msgs) ++{ ++ struct upnp_pending_message *p, *prev; ++ p = msgs; ++ while (p) { ++ prev = p; ++ p = p->next; ++ wpabuf_free(prev->msg); ++ os_free(prev); ++ } ++} ++ ++ ++int wps_attr_text(struct wpabuf *data, char *buf, char *end) ++{ ++ struct wps_parse_attr attr; ++ char *pos = buf; ++ int ret; ++ ++ if (wps_parse_msg(data, &attr) < 0) ++ return -1; ++ ++ if (attr.wps_state) { ++ if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) ++ ret = os_snprintf(pos, end - pos, ++ "wps_state=unconfigured\n"); ++ else if (*attr.wps_state == WPS_STATE_CONFIGURED) ++ ret = os_snprintf(pos, end - pos, ++ "wps_state=configured\n"); ++ else ++ ret = 0; ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.ap_setup_locked && *attr.ap_setup_locked) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_ap_setup_locked=1\n"); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.selected_registrar && *attr.selected_registrar) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_selected_registrar=1\n"); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.dev_password_id) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_device_password_id=%u\n", ++ WPA_GET_BE16(attr.dev_password_id)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.sel_reg_config_methods) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_selected_registrar_config_methods=" ++ "0x%04x\n", ++ WPA_GET_BE16(attr.sel_reg_config_methods)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.primary_dev_type) { ++ char devtype[WPS_DEV_TYPE_BUFSIZE]; ++ ret = os_snprintf(pos, end - pos, ++ "wps_primary_device_type=%s\n", ++ wps_dev_type_bin2str(attr.primary_dev_type, ++ devtype, ++ sizeof(devtype))); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.dev_name) { ++ char *str = os_malloc(attr.dev_name_len + 1); ++ size_t i; ++ if (str == NULL) ++ return pos - buf; ++ for (i = 0; i < attr.dev_name_len; i++) { ++ if (attr.dev_name[i] == 0 || ++ is_ctrl_char(attr.dev_name[i])) ++ str[i] = '_'; ++ else ++ str[i] = attr.dev_name[i]; ++ } ++ str[i] = '\0'; ++ ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); ++ os_free(str); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ if (attr.config_methods) { ++ ret = os_snprintf(pos, end - pos, ++ "wps_config_methods=0x%04x\n", ++ WPA_GET_BE16(attr.config_methods)); ++ if (os_snprintf_error(end - pos, ret)) ++ return pos - buf; ++ pos += ret; ++ } ++ ++ return pos - buf; ++} ++ ++ ++const char * wps_ei_str(enum wps_error_indication ei) ++{ ++ switch (ei) { ++ case WPS_EI_NO_ERROR: ++ return "No Error"; ++ case WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED: ++ return "TKIP Only Prohibited"; ++ case WPS_EI_SECURITY_WEP_PROHIBITED: ++ return "WEP Prohibited"; ++ case WPS_EI_AUTH_FAILURE: ++ return "Authentication Failure"; ++ default: ++ return "Unknown"; ++ } ++} +diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c +index 4ca3a42..f74b036 100644 +--- a/src/wps/wps_registrar.c ++++ b/src/wps/wps_registrar.c +@@ -589,9 +589,10 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg, + * These are the methods that the AP supports as an Enrollee for adding + * external Registrars. + */ +- methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; +- methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | +- WPS_CONFIG_PHY_PUSHBUTTON); ++ methods = reg->wps->config_methods; ++ //methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; ++ //methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | ++ // WPS_CONFIG_PHY_PUSHBUTTON); + wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); + wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); + wpabuf_put_be16(msg, 2); diff --git a/extras-buildpkgs/hostapd-realtek/debian/patches/series b/extras-buildpkgs/hostapd-realtek/debian/patches/series new file mode 100644 index 0000000000..8a362f8be2 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/patches/series @@ -0,0 +1,3 @@ +session-ticket.patch +300-noscan.patch +realtek.patch diff --git a/extras-buildpkgs/hostapd-realtek/debian/patches/session-ticket.patch b/extras-buildpkgs/hostapd-realtek/debian/patches/session-ticket.patch new file mode 100644 index 0000000000..09c2c35e44 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/patches/session-ticket.patch @@ -0,0 +1,21 @@ +From: Jeremy Nickurak +Subject: Disable the session ticket TLS extension. +Bug-ubuntu: https://bugs.launchpad.net/ubuntu/+source/wpasupplicant/+bug/969343 +Bug: http://w1.fi/bugz/show_bug.cgi?id=447 + +--- + src/crypto/tls_openssl.c | 1 + + 1 file changed, 1 insertion(+) + +Index: b/src/crypto/tls_openssl.c +=================================================================== +--- a/src/crypto/tls_openssl.c ++++ b/src/crypto/tls_openssl.c +@@ -1060,6 +1060,7 @@ struct tls_connection * tls_connection_i + #ifdef SSL_OP_NO_COMPRESSION + options |= SSL_OP_NO_COMPRESSION; + #endif /* SSL_OP_NO_COMPRESSION */ ++ options |= SSL_OP_NO_TICKET; + SSL_set_options(conn->ssl, options); + + conn->ssl_in = BIO_new(BIO_s_mem()); diff --git a/extras-buildpkgs/hostapd-realtek/debian/rules b/extras-buildpkgs/hostapd-realtek/debian/rules new file mode 100644 index 0000000000..e973bc7f5e --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/rules @@ -0,0 +1,67 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS=hardening=+all +include /usr/share/dpkg/buildflags.mk + +# The build system doesn't use CPPFLAGS, pass them to CFLAGS/CXXFLAGS to +# enable the missing (hardening) flags +DEB_CFLAGS_MAINT_APPEND = -MMD -Wall $(shell dpkg-buildflags --get CPPFLAGS) +DEB_CXXFLAGS_MAINT_APPEND = $(shell dpkg-buildflags --get CPPFLAGS) +DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed +export DEB_CFLAGS_MAINT_APPEND DEB_CXXFLAGS_MAINT_APPEND DEB_LDFLAGS_MAINT_APPEND + +UCFLAGS = -MMD -Wall -g -Os -fPIC + +BINDIR = /sbin +V = 1 + +DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) + CC=$(DEB_HOST_GNU_TYPE)-gcc +endif + +export CC BINDIR V + +VERSION := $(shell dpkg-parsechangelog | sed -ne 's,^Version: *\([0-9]*:\)\?\(.*\)$$,\2,p') + +override_dh_auto_build: + # build hostapd + cp -v --remove-destination debian/config/config_realtek hostapd/.config + dh_auto_build --sourcedirectory=hostapd \ + --buildsystem=makefile \ + --parallel + dh_auto_clean --sourcedirectory=src --buildsystem=makefile + +override_dh_auto_clean: + dh_auto_clean --sourcedirectory=hostapd \ + --buildsystem=makefile + +override_dh_auto_install: + $(info Skip dh_auto_install ...) + +override_dh_clean: + dh_clean hostapd/.config + +override_dh_install: + dh_install + install --mode=755 -D debian/ifupdown/hostapd.sh \ + debian/hostapd-realtek/etc/hostapd/ifupdown.sh + +override_dh_installchangelogs: + dh_installchangelogs --package=hostapd-realtek hostapd/ChangeLog + +override_dh_gencontrol: + dh_gencontrol -phostapd-realtek -- '-v1:$(VERSION)' + dh_gencontrol --remaining-packages + +override_dh_builddeb: + dh_builddeb -- -Zxz -z6 +### end dh overrides + +%: + dh ${@} --parallel + +get-orig-source: + chmod +x $(CURDIR)/debian/get-orig-source + $(CURDIR)/debian/get-orig-source $(CURDIR) diff --git a/extras-buildpkgs/hostapd-realtek/debian/source/format b/extras-buildpkgs/hostapd-realtek/debian/source/format new file mode 100644 index 0000000000..163aaf8d82 --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/extras-buildpkgs/hostapd-realtek/debian/source/options b/extras-buildpkgs/hostapd-realtek/debian/source/options new file mode 100644 index 0000000000..b3062866cf --- /dev/null +++ b/extras-buildpkgs/hostapd-realtek/debian/source/options @@ -0,0 +1,2 @@ +compression = "xz" +compression-level = 6 diff --git a/extras-buildpkgs/hostapd/debian/control b/extras-buildpkgs/hostapd/debian/control index 99ea6f7741..3ad71e62c8 100644 --- a/extras-buildpkgs/hostapd/debian/control +++ b/extras-buildpkgs/hostapd/debian/control @@ -31,6 +31,8 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base Breaks: initscripts (<< 2.88dsf-13.3) +Provides: hostapd +Conflicts: hostapd-realtek Description: IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator Originally, hostapd was an optional user space component for Host AP driver. It adds more features to the basic IEEE 802.11 management diff --git a/extras-buildpkgs/hostapd/debian/patches/realtek.patch b/extras-buildpkgs/hostapd/debian/patches/realtek.patch deleted file mode 100644 index f6052e99da..0000000000 --- a/extras-buildpkgs/hostapd/debian/patches/realtek.patch +++ /dev/null @@ -1,651 +0,0 @@ -diff --git a/hostapd/main.c b/hostapd/main.c -index a9d7da5..2457f95 100644 ---- a/hostapd/main.c -+++ b/hostapd/main.c -@@ -412,7 +412,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, - static void show_version(void) - { - fprintf(stderr, -- "hostapd v" VERSION_STR "\n" -+ "hostapd v" VERSION_STR " for Realtek rtl871xdrv\n" - "User space daemon for IEEE 802.11 AP management,\n" - "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2014, Jouni Malinen " -diff --git a/src/ap/beacon.c b/src/ap/beacon.c -index 2a4acf2..20d7451 100644 ---- a/src/ap/beacon.c -+++ b/src/ap/beacon.c -@@ -810,6 +810,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, - #ifdef CONFIG_IEEE80211N - tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); - tailpos = hostapd_eid_ht_operation(hapd, tailpos); -+ -+ //DRIVER_RTW ADD -+ if(hapd->iconf->ieee80211n) -+ hapd->conf->wmm_enabled = 1; -+ - #endif /* CONFIG_IEEE80211N */ - - tailpos = hostapd_eid_ext_capab(hapd, tailpos); -diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c -index 4e66d1b..620f246 100644 ---- a/src/ap/hw_features.c -+++ b/src/ap/hw_features.c -@@ -712,7 +712,10 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) - iface->num_ht40_scan_tries = 1; - eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL); - eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL); -- return 1; -+ -+ //DRIVER_RTW Modify -+ //return -1; -+ return 0;//ignore this error - } - - if (ret < 0) { -diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c -index ca64d5c..05606f0 100644 ---- a/src/drivers/driver_bsd.c -+++ b/src/drivers/driver_bsd.c -@@ -47,6 +47,12 @@ - - #include "l2_packet/l2_packet.h" - -+#ifdef HOSTAPD -+#ifdef CONFIG_SUPPORT_RTW_DRIVER -+#define RTW_BSD_HOSTAPD_SET_BEACON (1100) -+#endif -+#endif -+ - struct bsd_driver_data { - struct hostapd_data *hapd; /* back pointer */ - -@@ -792,6 +798,296 @@ handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) - drv_event_eapol_rx(drv->hapd, src_addr, buf, len); - } - -+#ifdef CONFIG_SUPPORT_RTW_DRIVER -+static int rtw_set_beacon_ops(void *priv, const u8 *head, size_t head_len, -+ const u8 *tail, size_t tail_len, int dtim_period, -+ int beacon_int) -+{ -+ int ret=0; -+ u8 *pbuf; -+ size_t sz; -+ struct bsd_driver_data *drv = priv; -+ -+ if((head_len<24) ||(!head)) -+ return -1; -+ -+ sz = head_len+tail_len - 24; // 24 = wlan hdr -+ -+ printf("%s, beacon_sz=%d\n", __func__, sz); -+ -+ pbuf = os_zalloc(sz); -+ if (pbuf == NULL) { -+ return -ENOMEM; -+ } -+ -+ os_memcpy(pbuf, (head+24), (head_len-24));// 24=beacon header len. -+ -+ os_memcpy(&pbuf[head_len-24], tail, tail_len); -+ -+ ret = set80211var(drv, RTW_BSD_HOSTAPD_SET_BEACON, pbuf, sz); -+ -+ os_free(pbuf); -+ -+ return ret; -+ -+} -+ -+static struct hostapd_hw_modes *rtw_get_hw_feature_data_ops( -+ void *priv, u16 *num_modes, u16 *flags) -+{ -+ -+#define MAX_NUM_CHANNEL (14) -+#define MAX_NUM_CHANNEL_5G (24) -+ -+ struct hostapd_hw_modes *modes; -+ size_t i; -+ int k; -+ -+ printf("%s\n", __func__); -+ -+ *num_modes = 3; -+ *flags = 0; -+ -+ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); -+ if (modes == NULL) -+ return NULL; -+ -+ //.1 -+ modes[0].mode = HOSTAPD_MODE_IEEE80211G; -+ modes[0].num_channels = MAX_NUM_CHANNEL; -+ modes[0].num_rates = 12; -+ modes[0].channels = -+ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); -+ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); -+ if (modes[0].channels == NULL || modes[0].rates == NULL) -+ goto fail; -+ for (i = 0; i < MAX_NUM_CHANNEL; i++) { -+ modes[0].channels[i].chan = i + 1; -+ modes[0].channels[i].freq = 2412 + 5 * i; -+ modes[0].channels[i].flag = 0; -+ if (i >= 13) -+ modes[0].channels[i].flag = HOSTAPD_CHAN_DISABLED; -+ } -+ modes[0].rates[0] = 10; -+ modes[0].rates[1] = 20; -+ modes[0].rates[2] = 55; -+ modes[0].rates[3] = 110; -+ modes[0].rates[4] = 60; -+ modes[0].rates[5] = 90; -+ modes[0].rates[6] = 120; -+ modes[0].rates[7] = 180; -+ modes[0].rates[8] = 240; -+ modes[0].rates[9] = 360; -+ modes[0].rates[10] = 480; -+ modes[0].rates[11] = 540; -+ -+ -+ //.2 -+ modes[1].mode = HOSTAPD_MODE_IEEE80211B; -+ modes[1].num_channels = MAX_NUM_CHANNEL; -+ modes[1].num_rates = 4; -+ modes[1].channels = -+ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); -+ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); -+ if (modes[1].channels == NULL || modes[1].rates == NULL) -+ goto fail; -+ for (i = 0; i < MAX_NUM_CHANNEL; i++) { -+ modes[1].channels[i].chan = i + 1; -+ modes[1].channels[i].freq = 2412 + 5 * i; -+ modes[1].channels[i].flag = 0; -+ if (i >= 11) -+ modes[1].channels[i].flag = HOSTAPD_CHAN_DISABLED; -+ } -+ modes[1].rates[0] = 10; -+ modes[1].rates[1] = 20; -+ modes[1].rates[2] = 55; -+ modes[1].rates[3] = 110; -+ -+ -+ //.3 -+ modes[2].mode = HOSTAPD_MODE_IEEE80211A; -+#ifdef CONFIG_DRIVER_RTL_DFS -+ modes[2].num_channels = MAX_NUM_CHANNEL_5G; -+#else /* CONFIG_DRIVER_RTL_DFS */ -+ modes[2].num_channels = 9; -+#endif /* CONFIG_DRIVER_RTL_DFS */ -+ -+ modes[2].num_rates = 8; -+ modes[2].channels = os_zalloc(modes[2].num_channels * sizeof(struct hostapd_channel_data)); -+ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); -+ if (modes[2].channels == NULL || modes[2].rates == NULL) -+ goto fail; -+ -+ -+ k = 0; -+ // 5G band1 Channel: 36, 40, 44, 48 -+ for (i=0; i < 4; i++) { -+ modes[2].channels[k].chan = 36+(i*4); -+ modes[2].channels[k].freq = 5180+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+#ifdef CONFIG_DRIVER_RTL_DFS -+ // 5G band2 Channel: 52, 56, 60, 64 -+ for (i=0; i < 4; i++) { -+ modes[2].channels[k].chan = 52+(i*4); -+ modes[2].channels[k].freq = 5260+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+ // 5G band3 Channel: 100, 104, 108. 112, 116, 120, 124, 128, 132, 136, 140 -+ for (i=0; i < 11; i++) { -+ modes[2].channels[k].chan = 100+(i*4); -+ modes[2].channels[k].freq = 5500+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+#endif /* CONFIG_DRIVER_RTL_DFS */ -+ -+ // 5G band4 Channel: 149, 153, 157, 161, 165 -+ for (i=0; i < 5; i++) { -+ modes[2].channels[k].chan = 149+(i*4); -+ modes[2].channels[k].freq = 5745+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+ modes[2].rates[0] = 60; -+ modes[2].rates[1] = 90; -+ modes[2].rates[2] = 120; -+ modes[2].rates[3] = 180; -+ modes[2].rates[4] = 240; -+ modes[2].rates[5] = 360; -+ modes[2].rates[6] = 480; -+ modes[2].rates[7] = 540; -+ -+ -+ // -+#if 0 -+#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) -+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) -+#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) -+#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) -+#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) -+#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) -+#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) -+#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) -+#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) -+#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) -+#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) -+#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) -+#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) -+#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) -+#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) -+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) -+#endif -+ -+ //HOSTAPD_MODE_IEEE80211G -+ modes[0].ht_capab = HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET|HT_CAP_INFO_SHORT_GI20MHZ| -+ HT_CAP_INFO_SHORT_GI40MHZ|HT_CAP_INFO_MAX_AMSDU_SIZE|HT_CAP_INFO_DSSS_CCK40MHZ; -+ -+ modes[0].mcs_set[0]= 0xff; -+ modes[0].mcs_set[1]= 0xff; -+ -+ //HOSTAPD_MODE_IEEE80211B -+ modes[1].ht_capab = 0; -+ -+ //HOSTAPD_MODE_IEEE80211A -+ modes[2].ht_capab = modes[0].ht_capab; -+ -+ modes[2].mcs_set[0]= 0xff; -+ modes[2].mcs_set[1]= 0xff; -+ -+ return modes; -+ -+fail: -+ if (modes) { -+ for (i = 0; i < *num_modes; i++) { -+ os_free(modes[i].channels); -+ os_free(modes[i].rates); -+ } -+ os_free(modes); -+ } -+ -+ return NULL; -+ -+} -+ -+#if 0 -+#define IEEE80211_FC0_TYPE_MASK 0x0c -+#define IEEE80211_FC0_TYPE_SHIFT 2 -+#define IEEE80211_FC0_TYPE_MGT 0x00 -+#define IEEE80211_FC0_TYPE_CTL 0x04 -+#define IEEE80211_FC0_TYPE_DATA 0x08 -+#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 -+#define IEEE80211_FC0_SUBTYPE_SHIFT 4 -+#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 -+#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 -+#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 -+#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 -+#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 -+#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 -+#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 -+#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 -+#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 -+#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 -+#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 -+#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 -+#define IEEE80211_FC0_SUBTYPE_ACTION_NOACK 0xe0 -+ -+#define IEEE80211_APPIE_WPA (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON | \ -+ IEEE80211_FC0_SUBTYPE_PROBE_RESP) -+ -+#endif -+ -+#define RTW_IEEE80211_APPIE_BEACON (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_BEACON) -+#define RTW_IEEE80211_APPIE_PROBE_RESP (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_PROBE_RESP) -+#define RTW_IEEE80211_APPIE_ASSOC_RESP (IEEE80211_FC0_TYPE_MGT|IEEE80211_FC0_SUBTYPE_ASSOC_RESP) -+ -+ -+static int rtw_set_wps_assoc_resp_ie(void *priv, const void *ie, size_t len) -+{ -+ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_ASSOC_RESP, -+ ie, len); -+} -+ -+static int rtw_set_wps_beacon_ie(void *priv, const void *ie, size_t len) -+{ -+ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_BEACON, -+ ie, len); -+} -+ -+static int rtw_set_wps_probe_resp_ie(void *priv, const void *ie, size_t len) -+{ -+ return bsd_set80211(priv, IEEE80211_IOC_APPIE, RTW_IEEE80211_APPIE_PROBE_RESP, -+ ie, len); -+} -+ -+static int rtw_set_ap_wps_ie_ops(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, const struct wpabuf *assocresp) -+{ -+ if (rtw_set_wps_assoc_resp_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, -+ assocresp ? wpabuf_len(assocresp) : 0)) -+ return -1; -+ -+ if (rtw_set_wps_beacon_ie(priv, beacon ? wpabuf_head(beacon) : NULL, -+ beacon ? wpabuf_len(beacon) : 0)) -+ return -1; -+ -+ return rtw_set_wps_probe_resp_ie(priv, -+ proberesp ? wpabuf_head(proberesp) : NULL, -+ proberesp ? wpabuf_len(proberesp): 0); -+ -+} -+#endif -+ -+ - static void * - bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) - { -@@ -844,6 +1140,12 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) - goto bad; - } - -+#ifdef CONFIG_SUPPORT_RTW_DRIVER -+ /* mark up after init */ -+ if (bsd_ctrl_iface(drv, 1) < 0) -+ goto bad; -+#endif -+ - return drv; - bad: - if (drv->sock_xmit != NULL) -@@ -1282,6 +1584,15 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) - event.interface_status.ifname); - wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); - } -+ else{ -+ os_strlcpy(event.interface_status.ifname, drv->ifname, -+ sizeof(event.interface_status.ifname)); -+ event.interface_status.ievent = EVENT_INTERFACE_ADDED; -+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", -+ event.interface_status.ifname); -+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); -+ } -+ - break; - } - } -@@ -1594,7 +1905,52 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) - } - #endif /* HOSTAPD */ - -- -+#ifdef CONFIG_SUPPORT_RTW_DRIVER -+const struct wpa_driver_ops wpa_driver_bsd_ops = { -+ .name = "bsd", -+ .desc = "BSD 802.11 support", -+#ifdef HOSTAPD -+ .hapd_init = bsd_init, -+ .hapd_deinit = bsd_deinit, -+ .set_privacy = bsd_set_privacy,//del ? -+ .get_seqnum = bsd_get_seqnum,//del ? -+ .flush = bsd_flush, -+ .read_sta_data = bsd_read_sta_driver_data,//del ? -+ .sta_disassoc = bsd_sta_disassoc, -+ .sta_deauth = bsd_sta_deauth, -+ .get_hw_feature_data = rtw_get_hw_feature_data_ops,//add -+ //.sta_remove = rtl871x_sta_remove_ops,//add -+ .set_beacon = rtw_set_beacon_ops, //add -+ .set_ap_wps_ie = rtw_set_ap_wps_ie_ops,//add -+#else /* HOSTAPD */ -+ .init = wpa_driver_bsd_init, -+ .deinit = wpa_driver_bsd_deinit, -+ .get_bssid = wpa_driver_bsd_get_bssid, -+ .get_ssid = wpa_driver_bsd_get_ssid, -+ .set_countermeasures = wpa_driver_bsd_set_countermeasures, -+ .scan2 = wpa_driver_bsd_scan, -+ .get_scan_results2 = wpa_driver_bsd_get_scan_results2, -+ .deauthenticate = wpa_driver_bsd_deauthenticate, -+ .disassociate = wpa_driver_bsd_disassociate, -+ .associate = wpa_driver_bsd_associate, -+ .get_capa = wpa_driver_bsd_get_capa, -+ .set_freq = bsd_set_freq, //only for wpa_supplicant -+ .set_ieee8021x = bsd_set_ieee8021x,//only for wpa_supplicant -+ .hapd_set_ssid = bsd_set_ssid,//only for wpa_supplicant -+ .hapd_get_ssid = bsd_get_ssid,//only for wpa_supplicant -+ .sta_set_flags = bsd_set_sta_authorized, //only for wpa_supplicant -+ .set_generic_elem = bsd_set_opt_ie, //only for wpa_supplicant -+#endif /* HOSTAPD */ -+ //.set_freq = bsd_set_freq, //only for wpa_supplicant -+ .set_key = bsd_set_key, -+ //.set_ieee8021x = bsd_set_ieee8021x, //only for wpa_supplicant -+ //.hapd_set_ssid = bsd_set_ssid, //only for wpa_supplicant -+ //.hapd_get_ssid = bsd_get_ssid, //only for wpa_supplicant -+ .hapd_send_eapol = bsd_send_eapol, //only for wpa_supplicant -+ //.sta_set_flags = bsd_set_sta_authorized, //only for wpa_supplicant -+ //.set_generic_elem = bsd_set_opt_ie, //only for wpa_supplicant -+}; -+#else - const struct wpa_driver_ops wpa_driver_bsd_ops = { - .name = "bsd", - .desc = "BSD 802.11 support", -@@ -1629,3 +1985,4 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { - .hapd_send_eapol = bsd_send_eapol, - .set_generic_elem = bsd_set_opt_ie, - }; -+#endif -diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c -index e5734bd..80f073d 100644 ---- a/src/drivers/driver_wext.c -+++ b/src/drivers/driver_wext.c -@@ -990,6 +990,38 @@ void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) - wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); - } - -+//added for wps2.0 @20110519 -+static int wpa_driver_wext_set_probe_req_ie(struct wpa_driver_wext_data *drv, const u8 *extra_ies, -+ size_t extra_ies_len) -+{ -+ unsigned char *pbuf; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ pbuf = os_malloc(extra_ies_len); -+ os_memset(pbuf, 0, extra_ies_len); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ os_memcpy(pbuf, extra_ies, extra_ies_len); -+ -+ iwr.u.data.pointer = (caddr_t)pbuf; -+ iwr.u.data.length = extra_ies_len; -+ iwr.u.data.flags = 0x8766;//magic number -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMLME]"); -+ ret = -1; -+ } -+ -+ if(pbuf) -+ os_free(pbuf); -+ -+ return ret; -+ -+} -+ - - /** - * wpa_driver_wext_scan - Request the driver to initiate scan -@@ -1012,6 +1044,10 @@ int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) - return -1; - } - -+ //added for wps2.0 @20110519 -+ wpa_driver_wext_set_probe_req_ie(drv, params->extra_ies, -+ params->extra_ies_len); -+ - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - -@@ -2315,6 +2351,28 @@ static const char * wext_get_radio_name(void *priv) - return drv->phyname; - } - -+// Aries 20120120, append rssi information at the end of "status" command -+int wext_signal_poll(void *priv, struct wpa_signal_info *signal_info) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ struct iw_statistics stat; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_memset(&stat, 0, sizeof(stat)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) &stat; -+ iwr.u.data.length = sizeof(struct iw_statistics); -+ iwr.u.data.flags = 1; -+ if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { -+ perror("ioctl[SIOCGIWSTATS] fail\n"); -+ ret = -1; -+ } -+ signal_info->current_signal = stat.qual.level; -+ signal_info->current_noise = stat.qual.noise; -+ return ret; -+} - - const struct wpa_driver_ops wpa_driver_wext_ops = { - .name = "wext", -diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c -index d0e42ec..d413c00 100644 ---- a/src/drivers/drivers.c -+++ b/src/drivers/drivers.c -@@ -51,6 +51,9 @@ extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ - #ifdef CONFIG_DRIVER_NONE - extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ - #endif /* CONFIG_DRIVER_NONE */ -+#ifdef CONFIG_DRIVER_RTW -+extern struct wpa_driver_ops wpa_driver_rtw_ops; /* driver_rtw.c */ -+#endif /* CONFIG_DRIVER_RTW */ - - - struct wpa_driver_ops *wpa_drivers[] = -@@ -94,5 +97,8 @@ struct wpa_driver_ops *wpa_drivers[] = - #ifdef CONFIG_DRIVER_NONE - &wpa_driver_none_ops, - #endif /* CONFIG_DRIVER_NONE */ -+#ifdef CONFIG_DRIVER_RTW -+ &wpa_driver_rtw_ops, -+#endif /* CONFIG_DRIVER_RTW */ - NULL - }; -diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak -index 7e175f4..b5881db 100644 ---- a/src/drivers/drivers.mak -+++ b/src/drivers/drivers.mak -@@ -58,6 +58,10 @@ DRV_CFLAGS += -DCONFIG_DRIVER_BSD - DRV_OBJS += ../src/drivers/driver_bsd.o - CONFIG_L2_FREEBSD=y - CONFIG_DNET_PCAP=y -+ifdef CONFIG_SUPPORT_RTW_DRIVER -+DRV_CFLAGS += -DCONFIG_SUPPORT_RTW_DRIVER -DCONFIG_DRIVER_RTL_DFS -+NEED_AP_MLME=y -+endif - endif - - ifdef CONFIG_DRIVER_OPENBSD -@@ -74,6 +78,17 @@ DRV_OBJS += ../src/drivers/driver_test.o - NEED_AP_MLME=y - endif - -+ifdef CONFIG_DRIVER_RTW -+#CFLAGS += -DCONFIG_DRIVER_RTL -+#OBJS += driver_rtl.o -+DRV_AP_CFLAGS += -DCONFIG_DRIVER_RTW -DCONFIG_DRIVER_RTL_DFS -+DRV_AP_OBJS += ../src/drivers/driver_rtw.o -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_AP_MLME=y -+endif -+ - ifdef CONFIG_DRIVER_NONE - DRV_CFLAGS += -DCONFIG_DRIVER_NONE - DRV_OBJS += ../src/drivers/driver_none.o -diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c -index 23e9823..173e71d 100644 ---- a/src/eap_peer/eap_wsc.c -+++ b/src/eap_peer/eap_wsc.c -@@ -566,8 +566,13 @@ send_msg: - r = eap_wsc_build_msg(data, ret, id); - if (data->state == FAIL && ret->methodState == METHOD_DONE) { - /* Use reduced client timeout for WPS to avoid long wait */ -+#if 0 /* Aries add, 2012/06/12, extend timeout for AP IOT */ -+ if (sm->ClientTimeout > 4) -+ sm->ClientTimeout = 4; -+#else - if (sm->ClientTimeout > 2) - sm->ClientTimeout = 2; -+#endif - } - return r; - } -diff --git a/src/wps/wps.c b/src/wps/wps.c -index 648cfd1..0a74d0c 100644 ---- a/src/wps/wps.c -+++ b/src/wps/wps.c -@@ -320,11 +320,15 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, - if (wps_parse_msg(msg, &attr) < 0) - return 0; - -+ return is_selected_pin_registrar(&attr); -+// Marked by Albert 2011/11/17 -+// Some APs won't carry the AuthorizedMACs in the probe response. -+// So, skip this check will speed up the process to find the current AP out for WPS handshake. -+/* - if (!attr.version2 && ver1_compat) { - /* - * Version 1.0 AP - AuthorizedMACs not used, so revert back to - * old mechanism of using SelectedRegistrar. -- */ - return is_selected_pin_registrar(&attr); - } - -@@ -341,6 +345,7 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, - } - - return 0; -+*/ - } - - -diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c -index b917e6b..4738fd5 100644 ---- a/src/wps/wps_registrar.c -+++ b/src/wps/wps_registrar.c -@@ -589,9 +589,10 @@ static int wps_build_probe_config_methods(struct wps_registrar *reg, - * These are the methods that the AP supports as an Enrollee for adding - * external Registrars. - */ -- methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; -- methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | -- WPS_CONFIG_PHY_PUSHBUTTON); -+ methods = reg->wps->config_methods; -+ //methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; -+ //methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | -+ // WPS_CONFIG_PHY_PUSHBUTTON); - wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); - wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); - wpabuf_put_be16(msg, 2); diff --git a/extras-buildpkgs/xf86-video-fbturbo/debian/rules b/extras-buildpkgs/xf86-video-fbturbo/debian/rules index 0b10938dbe..90a1680867 100644 --- a/extras-buildpkgs/xf86-video-fbturbo/debian/rules +++ b/extras-buildpkgs/xf86-video-fbturbo/debian/rules @@ -4,8 +4,8 @@ # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -override_dh_autoreconf: - dh_autoreconf --with-xorg-module-dir="/usr/lib/xorg/modules" +override_dh_auto_configure: + dh_auto_configure -- --prefix=/usr --with-xorg-module-dir="/usr/lib/xorg/modules" override_dh_auto_install: dh_auto_install diff --git a/general.sh b/general.sh index 374289984d..6b6c4adaf3 100644 --- a/general.sh +++ b/general.sh @@ -42,7 +42,7 @@ cleaning() display_alert "Cleaning $DEST/debs for" "$BOARD $BRANCH" "info" # easier than dealing with variable expansion and escaping dashes in file names find $DEST/debs -name '*.deb' | grep -E "${CHOSEN_KERNEL/image/.*}|$CHOSEN_UBOOT" | xargs rm -f - [[ -n $RELEASE ]] && rm -f $DEST/debs/$RELEASE/${CHOSEN_ROOTFS}_${REVISION}_${ARCH}.deb + [[ -n $RELEASE ]] && rm -f $DEST/debs/$RELEASE/${CHOSEN_ROOTFS}_*_${ARCH}.deb fi ;; diff --git a/main.sh b/main.sh index ff27a78bcf..13c71a352e 100644 --- a/main.sh +++ b/main.sh @@ -52,9 +52,6 @@ if [[ -z $ver1 || $ver1 -lt $ver2 ]]; then read fi -# clean unfinished DEB packing -rm -rf $DEST/debs/*/*/ - # Script parameters handling for i in "$@"; do if [[ $i == *=* ]]; then