Merge hostapd / wpa_supplicant 2.0.

Reviewed by:	adrian (driver_bsd + usr.sbin/wpa)
This commit is contained in:
Rui Paulo 2013-07-04 21:12:58 +00:00
commit f05cddf940
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=252726
587 changed files with 95162 additions and 23074 deletions

View File

@ -1,340 +1,22 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
wpa_supplicant and hostapd
--------------------------
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Also add information on how to contact you by electronic and paper mail.
See the README file for the current license terms.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
This software was previously distributed under BSD/GPL v2 dual license
terms that allowed either of those license alternatives to be
selected. As of February 11, 2012, the project has chosen to use only
the BSD license option for future distribution. As such, the GPL v2
license option is no longer used. It should be noted that the BSD
license option (the one with advertisement clause removed) is compatible
with GPL and as such, does not prevent use of this software in projects
that use GPL.
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
Some of the files may still include pointers to GPL version 2 license
terms. However, such copyright and license notifications are maintained
only for attribution purposes and any distribution of this software
after February 11, 2012 is no longer under the GPL v2 option.

View File

@ -1,19 +1,56 @@
wpa_supplicant and hostapd v0.6.x
---------------------------------
wpa_supplicant and hostapd
--------------------------
Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These program is dual-licensed under both the GPL version 2 and BSD
license. Either license may be used at your option.
These programs are licensed under the BSD license (the one with
advertisement clause removed).
If you are submitting changes to the project, please see CONTRIBUTIONS
file for more instructions.
This package may include either wpa_supplicant, hostapd, or both. See
README file respective subdirectories (wpa_supplicant/README or
hostapd/README) for more details.
Source code files have been moved around in v0.6.x releases and
compared to earlier releases, the programs are now build by first
going to a subdirectory (wpa_supplicant or hostapd) and creating
build configuration (.config) and running 'make' there (for
Linux/BSD/cygwin builds).
Source code files were moved around in v0.6.x releases and compared to
earlier releases, the programs are now built by first going to a
subdirectory (wpa_supplicant or hostapd) and creating build
configuration (.config) and running 'make' there (for Linux/BSD/cygwin
builds).
License
-------
This software may be distributed, used, and modified under the terms of
BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,7 +0,0 @@
*.d
.config
driver_conf.c
hostapd
hostapd_cli
hlr_auc_gw
nt_password_hash

View File

@ -1,20 +1,206 @@
ChangeLog for hostapd
2010-09-07 - v0.7.3
* fixed re-association after WPS not initializing WPA state machine in
some cases
* fixed WPS IE update on reconfiguration
* fixed WPS code not to proxy Probe Request frames for foreign SSIDs
* added WPS workaround for open networks and some known interop issues
* fixed WPS Diffie-Hellman derivation to use correct public key length
* fixed FT RRB messages on big endian CPUs
* changed WPS protection for brute force AP PIN attacks to disable AP
PIN only temporarily (but with increasing time) to avoid usability
issues on Label-only devices
* added wps_ap_pin command for more secure handling of AP PIN
operations (e.g., to generate a random AP PIN and only use it for
short amount of time)
* fixed HT STBC negotiation
2013-01-12 - v2.0
* added AP-STA-DISCONNECTED ctrl_iface event
* improved debug logging (human readable event names, interface name
included in more entries)
* added number of small changes to make it easier for static analyzers
to understand the implementation
* added a workaround for Windows 7 Michael MIC failure reporting and
use of the Secure bit in EAPOL-Key msg 3/4
* fixed number of small bugs (see git logs for more details)
* changed OpenSSL to read full certificate chain from server_cert file
* nl80211: number of updates to use new cfg80211/nl80211 functionality
- replace monitor interface with nl80211 commands
- additional information for driver-based AP SME
* EAP-pwd:
- fix KDF for group 21 and zero-padding
- added support for fragmentation
- increased maximum number of hunting-and-pecking iterations
* avoid excessive Probe Response retries for broadcast Probe Request
frames (only with drivers using hostapd SME/MLME)
* added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
* fixed WPS operation stopping on dual concurrent AP
* added wps_rf_bands configuration parameter for overriding RF Bands
value for WPS
* added support for getting per-device PSK from RADIUS Tunnel-Password
* added support for libnl 3.2 and newer
* increased initial group key handshake retransmit timeout to 500 ms
* added a workaround for 4-way handshake to update SNonce even after
having sent EAPOL-Key 3/4 to avoid issues with some supplicant
implementations that can change SNonce for each EAP-Key 2/4
* added a workaround for EAPOL-Key 4/4 using incorrect type value in
WPA2 mode (some deployed stations use WPA type in that message)
* added a WPS workaround for mixed mode AP Settings with Windows 7
* changed WPS AP PIN disabling mechanism to disable the PIN after 10
consecutive failures in addition to using the exponential lockout
period
* added support for WFA Hotspot 2.0
- GAS/ANQP advertisement of network information
- disable_dgaf parameter to disable downstream group-addressed
forwarding
* simplified licensing terms by selecting the BSD license as the only
alternative
* EAP-SIM: fixed re-authentication not to update pseudonym
* EAP-SIM: use Notification round before EAP-Failure
* EAP-AKA: added support for AT_COUNTER_TOO_SMALL
* EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
* EAP-AKA': fixed identity for MK derivation
* EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
breaks interoperability with older versions
* EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
* changed ANonce to be a random number instead of Counter-based
* added support for canceling WPS operations with hostapd_cli wps_cancel
* fixed EAP/WPS to PSK transition on reassociation in cases where
deauthentication is missed
* hlr_auc_gw enhancements:
- a new command line parameter -u can be used to enable updating of
SQN in Milenage file
- use 5 bit IND for SQN updates
- SQLite database can now be used to store Milenage information
* EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
and reauth data
* added support for Chargeable-User-Identity (RFC 4372)
* added radius_auth_req_attr and radius_acct_req_attr configuration
parameters to allow adding/overriding of RADIUS attributes in
Access-Request and Accounting-Request packets
* added support for RADIUS dynamic authorization server (RFC 5176)
* added initial support for WNM operations
- BSS max idle period
- WNM-Sleep Mode
* added new WPS NFC ctrl_iface mechanism
- removed obsoleted WPS_OOB command (including support for deprecated
UFD config_method)
* added FT support for drivers that implement MLME internally
* added SA Query support for drivers that implement MLME internally
* removed default ACM=1 from AC_VO and AC_VI
* changed VENDOR-TEST EAP method to use proper private enterprise number
(this will not interoperate with older versions)
* added hostapd.conf parameter vendor_elements to allow arbitrary vendor
specific elements to be added to the Beacon and Probe Response frames
* added support for configuring GCMP cipher for IEEE 802.11ad
* added support for 256-bit AES with internal TLS implementation
* changed EAPOL transmission to use AC_VO if WMM is active
* fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
correctly; invalid messages could have caused the hostapd process to
terminate before this fix [CVE-2012-4445]
* limit number of active wildcard PINs for WPS Registrar to one to avoid
confusing behavior with multiple wildcard PINs
* added a workaround for WPS PBC session overlap detection to avoid
interop issues with deployed station implementations that do not
remove active PBC indication from Probe Request frames properly
* added support for using SQLite for the eap_user database
* added Acct-Session-Id attribute into Access-Request messages
* fixed EAPOL frame transmission to non-QoS STAs with nl80211
(do not send QoS frames if the STA did not negotiate use of QoS for
this association)
2012-05-10 - v1.0
* Add channel selection support in hostapd. See hostapd.conf.
* Add support for IEEE 802.11v Time Advertisement mechanism with UTC
TSF offset. See hostapd.conf for config info.
* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
This allows the driver to use PS buffering of Deauthentication and
Disassociation frames when the STA is in power save sleep. Only
available with drivers that provide TX status events for Deauth/
Disassoc frames (nl80211).
* Allow PMKSA caching to be disabled on the Authenticator. See
hostap.conf config parameter disable_pmksa_caching.
* atheros: Add support for IEEE 802.11w configuration.
* bsd: Add support for setting HT values in IFM_MMASK.
* Allow client isolation to be configured with ap_isolate. Client
isolation can be used to prevent low-level bridging of frames
between associated stations in the BSS. By default, this bridging
is allowed.
* Allow coexistance of HT BSSes with WEP/TKIP BSSes.
* Add require_ht config parameter, which can be used to configure
hostapd to reject association with any station that does not support
HT PHY.
* Add support for writing debug log to a file using "-f" option. Also
add relog CLI command to re-open the log file.
* Add bridge handling for WDS STA interfaces. By default they are
added to the configured bridge of the AP interface (if present),
but the user can also specify a separate bridge using cli command
wds_bridge.
* hostapd_cli:
- Add wds_bridge command for specifying bridge for WDS STA
interfaces.
- Add relog command for reopening log file.
- Send AP-STA-DISCONNECTED event when an AP disconnects a station
due to inactivity.
- Add wps_config ctrl_interface command for configuring AP. This
command can be used to configure the AP using the internal WPS
registrar. It works in the same way as new AP settings received
from an ER.
- Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
- Add command get version, that returns hostapd version string.
* WNM: Add BSS Transition Management Request for ESS Disassoc Imminent.
Use hostapd_cli ess_disassoc (STA addr) (URL) to send the
notification to the STA.
* Allow AP mode to disconnect STAs based on low ACK condition (when
the data connection is not working properly, e.g., due to the STA
going outside the range of the AP). Disabled by default, enable by
config option disassoc_low_ack.
* Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
config file.
* WPS:
- Send AP Settings as a wrapped Credential attribute to ctrl_iface
in WPS-NEW-AP-SETTINGS.
- Dispatch more WPS events through hostapd ctrl_iface.
- Add mechanism for indicating non-standard WPS errors.
- Change concurrent radio AP to use only one WPS UPnP instance.
- Add wps_check_pin command for processing PIN from user input.
UIs can use this command to process a PIN entered by a user and to
validate the checksum digit (if present).
- Add hostap_cli get_config command to display current AP config.
- Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at
runtime and support dynamic AP PIN management.
- Disable AP PIN after 10 consecutive failures. Slow down attacks
on failures up to 10.
- Allow AP to start in Enrollee mode without AP PIN for probing,
to be compatible with Windows 7.
- Add Config Error into WPS-FAIL events to provide more info
to the user on how to resolve the issue.
- When controlling multiple interfaces:
- apply WPS commands to all interfaces configured to use WPS
- apply WPS config changes to all interfaces that use WPS
- when an attack is detected on any interface, disable AP PIN on
all interfaces
* WPS ER:
- Show SetSelectedRegistrar events as ctrl_iface events.
- Add special AP Setup Locked mode to allow read only ER.
ap_setup_locked=2 can now be used to enable a special mode where
WPS ER can learn the current AP settings, but cannot change them.
* WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
- Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
for testing protocol extensibility.
- Add build option CONFIG_WPS_STRICT to allow disabling of WPS
workarounds.
- Add support for AuthorizedMACs attribute.
* TDLS:
- Allow TDLS use or TDLS channel switching in the BSS to be
prohibited in the BSS, using config params tdls_prohibit and
tdls_prohibit_chan_switch.
* EAP server: Add support for configuring fragment size (see
fragment_size in hostapd.conf).
* wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
wlantest can be used to capture frames from a monitor interface
for realtime capturing or from pcap files for offline analysis.
* Interworking: Support added for 802.11u. Enable in .config with
CONFIG_INTERWORKING. See hostapd.conf for config parameters for
interworking.
* Android: Add build and runtime support for Android hostapd.
* Add a new debug message level for excessive information. Use
-ddd to enable.
* TLS: Add support for tls_disable_time_checks=1 in client mode.
* Internal TLS:
- Add support for TLS v1.1 (RFC 4346). Enable with build parameter
CONFIG_TLSV11.
- Add domainComponent parser for X.509 names
* Reorder some IEs to get closer to IEEE 802.11 standard. Move
WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
Move HT IEs to be later in (Re)Assoc Resp.
* Many bugfixes.
2010-04-18 - v0.7.2
* fix WPS internal Registrar use when an external Registrar is also
@ -98,7 +284,7 @@ ChangeLog for hostapd
* updated management frame protection to use IEEE Std 802.11w-2009
* fixed number of small WPS issues and added workarounds to
interoperate with common deployed broken implementations
* added some IEEE 802.11n co-existance rules to disable 40 MHz channels
* added some IEEE 802.11n co-existence rules to disable 40 MHz channels
or modify primary/secondary channels if needed based on neighboring
networks
* added support for NFC out-of-band mechanism with WPS

View File

@ -43,6 +43,7 @@ OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ieee802_1x.o
OBJS += ../src/ap/ap_config.o
OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/ieee802_11_auth.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/wpa_auth.o
@ -51,6 +52,10 @@ OBJS += ../src/ap/ap_mlme.o
OBJS += ../src/ap/wpa_auth_ie.o
OBJS += ../src/ap/preauth_auth.o
OBJS += ../src/ap/pmksa_cache_auth.o
OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/beacon.o
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
NEED_RC4=y
NEED_AES=y
@ -63,18 +68,25 @@ CFLAGS += -DHOSTAPD
ifdef CONFIG_WPA_TRACE
CFLAGS += -DWPA_TRACE
OBJS += ../src/utils/trace.o
HOBJS += ../src/utils/trace.o
LDFLAGS += -rdynamic
CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
CFLAGS += -DWPA_TRACE_BFD
LIBS += -lbfd
LIBS_c += -lbfd
LIBS_h += -lbfd
endif
endif
OBJS += ../src/utils/eloop.o
ifndef CONFIG_ELOOP
CONFIG_ELOOP=eloop
endif
OBJS += ../src/utils/$(CONFIG_ELOOP).o
OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
OBJS += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/os_$(CONFIG_OS).o
OBJS += ../src/utils/ip_addr.o
@ -99,6 +111,7 @@ CONFIG_NO_ACCOUNTING=y
else
OBJS += ../src/radius/radius.o
OBJS += ../src/radius/radius_client.o
OBJS += ../src/radius/radius_das.o
endif
ifdef CONFIG_NO_ACCOUNTING
@ -111,6 +124,12 @@ ifdef CONFIG_NO_VLAN
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
OBJS += ../src/ap/vlan_util.o
endif
CFLAGS += -DCONFIG_VLAN_NETLINK
endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@ -153,10 +172,23 @@ NEED_AES_OMAC1=y
NEED_AES_UNWRAP=y
endif
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
endif
ifdef CONFIG_WNM
CFLAGS += -DCONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
endif
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
include ../src/drivers/drivers.mak
OBJS += $(DRV_AP_OBJS)
CFLAGS += $(DRV_AP_CFLAGS)
@ -192,6 +224,14 @@ OBJS += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
endif
ifdef CONFIG_EAP_UNAUTH_TLS
CFLAGS += -DEAP_SERVER_UNAUTH_TLS
ifndef CONFIG_EAP_TLS
OBJS += ../src/eap_server/eap_server_tls.o
TLS_FUNCS=y
endif
endif
ifdef CONFIG_EAP_PEAP
CFLAGS += -DEAP_SERVER_PEAP
OBJS += ../src/eap_server/eap_server_peap.o
@ -274,6 +314,12 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_SERVER_PWD
OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
NEED_SHA256=y
endif
ifdef CONFIG_EAP_VENDOR_TEST
CFLAGS += -DEAP_SERVER_VENDOR_TEST
OBJS += ../src/eap_server/eap_server_vendor_test.o
@ -289,6 +335,10 @@ NEED_AES_UNWRAP=y
endif
ifdef CONFIG_WPS
ifdef CONFIG_WPS2
CFLAGS += -DCONFIG_WPS2
endif
CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
OBJS += ../src/utils/uuid.o
OBJS += ../src/ap/wps_hostapd.o
@ -308,25 +358,10 @@ NEED_AES_CBC=y
NEED_MODEXP=y
CONFIG_EAP=y
ifdef CONFIG_WPS_UFD
CFLAGS += -DCONFIG_WPS_UFD
OBJS += ../src/wps/wps_ufd.o
NEED_WPS_OOB=y
endif
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
ifdef CONFIG_WPS_NFC_PN531
PN531_PATH ?= /usr/local/src/nfc
CFLAGS += -DCONFIG_WPS_NFC_PN531
CFLAGS += -I${PN531_PATH}/inc
OBJS += ../src/wps/wps_nfc_pn531.o
LIBS += ${PN531_PATH}/lib/wpsnfc.dll
LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
endif
endif
ifdef NEED_WPS_OOB
@ -346,6 +381,15 @@ OBJS += ../src/wps/http_client.o
OBJS += ../src/wps/http_server.o
endif
ifdef CONFIG_WPS_STRICT
CFLAGS += -DCONFIG_WPS_STRICT
OBJS += ../src/wps/wps_validate.o
endif
ifdef CONFIG_WPS_TESTING
CFLAGS += -DCONFIG_WPS_TESTING
endif
endif
ifdef CONFIG_EAP_IKEV2
@ -406,6 +450,15 @@ ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
ifdef CONFIG_TLSV11
CFLAGS += -DCONFIG_TLSV11
endif
ifdef CONFIG_TLSV12
CFLAGS += -DCONFIG_TLSV12
NEED_SHA256=y
endif
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
@ -424,10 +477,6 @@ ifeq ($(CONFIG_TLS), gnutls)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_gnutls.o
LIBS += -lgnutls -lgpg-error
ifdef CONFIG_GNUTLS_EXTRA
CFLAGS += -DCONFIG_GNUTLS_EXTRA
LIBS += -lgnutls-extra
endif
endif
OBJS += ../src/crypto/crypto_gnutls.o
HOBJS += ../src/crypto/crypto_gnutls.o
@ -489,6 +538,9 @@ OBJS += ../src/tls/pkcs8.o
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
ifdef CONFIG_TLSV12
NEED_TLS_PRF_SHA256=y
endif
NEED_MODEXP=y
NEED_CIPHER=y
CFLAGS += -DCONFIG_TLS_INTERNAL
@ -602,14 +654,19 @@ OBJS += $(AESOBJS)
endif
ifdef NEED_SHA1
ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
endif
SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += ../src/crypto/fips_prf_internal.o
endif
endif
ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@ -625,6 +682,7 @@ endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
OBJS += ../src/crypto/md5-internal.o
HOBJS += ../src/crypto/md5-internal.o
endif
endif
@ -647,10 +705,17 @@ endif
endif
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/sha256.o
endif
OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
OBJS += ../src/crypto/sha256-internal.o
endif
ifdef NEED_TLS_PRF_SHA256
OBJS += ../src/crypto/sha256-tlsprf.o
endif
endif
ifdef NEED_DH_GROUPS
@ -665,6 +730,16 @@ OBJS += ../src/crypto/dh_group5.o
endif
endif
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
OBJS += ../src/crypto/random.o
HOBJS += ../src/crypto/random.o
HOBJS += ../src/utils/eloop.o
HOBJS += $(SHA1OBJS)
HOBJS += ../src/crypto/md5.o
endif
ifdef CONFIG_RADIUS_SERVER
CFLAGS += -DRADIUS_SERVER
OBJS += ../src/radius/radius_server.o
@ -689,7 +764,6 @@ OBJS += ../src/utils/base64.o
endif
ifdef NEED_AP_MLME
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
OBJS += ../src/ap/ieee802_11.o
@ -700,10 +774,49 @@ ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
endif
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
endif
ifdef CONFIG_P2P_MANAGER
CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += ../src/ap/p2p_hostapd.o
endif
ifdef CONFIG_HS20
CFLAGS += -DCONFIG_HS20
OBJS += ../src/ap/hs20.o
CONFIG_INTERWORKING=y
endif
ifdef CONFIG_INTERWORKING
CFLAGS += -DCONFIG_INTERWORKING
OBJS += ../src/common/gas.o
OBJS += ../src/ap/gas_serv.o
endif
OBJS += ../src/drivers/driver_common.o
ifdef CONFIG_WPA_CLI_EDIT
OBJS_c += ../src/utils/edit.o
else
OBJS_c += ../src/utils/edit_simple.o
endif
ifdef CONFIG_NO_STDOUT_DEBUG
CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
ifdef CONFIG_DEBUG_FILE
CFLAGS += -DCONFIG_DEBUG_FILE
endif
ifdef CONFIG_SQLITE
CFLAGS += -DCONFIG_SQLITE
LIBS += -lsqlite3
LIBS_h += -lsqlite3
endif
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@ -729,7 +842,8 @@ verify_config:
fi
install: all
for i in $(ALL); do cp -f $$i /usr/local/bin/$$i; done
mkdir -p $(DESTDIR)/usr/local/bin
for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
../src/drivers/build.hostapd:
@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
@ -740,15 +854,15 @@ install: all
BCHECK=../src/drivers/build.hostapd
hostapd: $(BCHECK) $(OBJS)
$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
ifdef CONFIG_WPA_TRACE
OBJS_c += ../src/utils/trace.o
OBJS_c += ../src/utils/wpa_debug.o
endif
hostapd_cli: $(OBJS_c)
$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
ifdef NEED_RC4
@ -778,10 +892,12 @@ HOBJS += ../src/crypto/aes-internal-enc.o
endif
nt_password_hash: $(NOBJS)
$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
@$(E) " LD " $@
hlr_auc_gw: $(HOBJS)
$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@
clean:
$(MAKE) -C ../src clean

View File

@ -2,37 +2,22 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> and contributors
Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is dual-licensed under both the GPL version 2 and BSD
license. Either license may be used at your option.
This program is licensed under the BSD license (the one with
advertisement clause removed).
If you are submitting changes to the project, please see CONTRIBUTIONS
file for more instructions.
License
-------
GPL v2:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(this copy of the license is in COPYING file)
Alternatively, this software may be distributed, used, and modified
under the terms of BSD license:
This software may be distributed, used, and modified under the terms of
BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are

View File

@ -63,8 +63,13 @@ includes WPS support and uses madwifi driver interface:
CONFIG_DRIVER_MADWIFI=y
CFLAGS += -I/usr/src/madwifi-0.9.3
CONFIG_WPS=y
CONFIG_WPS2=y
CONFIG_WPS_UPNP=y
Following parameter can be used to enable support for NFC config method:
CONFIG_WPS_NFC=y
Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
@ -119,6 +124,13 @@ pushbutton event (for PBC) to allow a new WPS Enrollee to join the
network. hostapd uses the control interface as an input channel for
these events.
The PIN value used in the commands must be processed by an UI to
remove non-digit characters and potentially, to verify the checksum
digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
the checksum digit is incorrect, or the processed PIN (non-digit
characters removed) if the PIN is valid.
When a client device (WPS Enrollee) connects to hostapd (WPS
Registrar) in order to start PIN mode negotiation for WPS, an
identifier (Enrollee UUID) is sent. hostapd will need to be configured
@ -171,10 +183,17 @@ hostapd_cli wps_pin any 12345670
To reduce likelihood of PIN being used with other devices or of
forgetting an active PIN available for potential attackers, expiration
time can be set for the new PIN:
time in seconds can be set for the new PIN (value 0 indicates no
expiration):
hostapd_cli wps_pin any 12345670 300
If the MAC address of the enrollee is known, it should be configured
to allow the AP to advertise list of authorized enrollees:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
12345670 300 00:11:22:33:44:55
After this, the Enrollee can connect to the AP again and complete WPS
negotiation. At that point, a new, random WPA PSK is generated for the
@ -221,6 +240,17 @@ hostapd_cli wps_ap_pin set <PIN> [timeout]
- if the optional timeout parameter is given, the AP PIN will be enabled
for the specified number of seconds
hostapd_cli get_config
- display the current configuration
hostapd_cli wps_config <new SSID> <auth> <encr> <new key>
examples:
hostapd_cli wps_config testing WPA2PSK CCMP 12345678
hostapd_cli wps_config "no security" OPEN NONE ""
<auth> must be one of the following: OPEN WPAPSK WPA2PSK
<encr> must be one of the following: NONE WEP TKIP CCMP
Credential generation and configuration changes
-----------------------------------------------
@ -251,7 +281,7 @@ WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
For example:
<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
This can be used to tricker change from unconfigured to configured
This can be used to trigger change from unconfigured to configured
state (random configuration based on the first successful WPS
registration). In addition, this can be used to update AP UI about the
status of WPS registration progress.
@ -263,3 +293,48 @@ For example:
This can be used to update the externally stored AP configuration and
then update hostapd configuration (followed by restarting of hostapd).
WPS with NFC
------------
WPS can be used with NFC-based configuration method. An NFC tag
containing a password token from the Enrollee can be used to
authenticate the connection instead of the PIN. In addition, an NFC tag
with a configuration token can be used to transfer AP settings without
going through the WPS protocol.
When the AP acts as an Enrollee, a local NFC tag with a password token
can be used by touching the NFC interface of an external Registrar. The
wps_nfc_token command is used to manage use of the NFC password token
from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
password token (in place of AP PIN) and "wps_nfc_token disable" disables
the NFC password token.
The NFC password token that is either pre-configured in the
configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
wpa_supplicant can be used to generate NFC password tokens during
manufacturing (each AP needs to have its own random keys).
The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
NFC configuration token. The output value from this command is a hexdump
of the current AP configuration (WPS parameter requests this to include
only the WPS attributes; NDEF parameter requests additional NDEF
encapsulation to be included). This data needs to be written to an NFC
tag with an external program. Once written, the NFC configuration token
can be used to touch an NFC interface on a station to provision the
credentials needed to access the network.
When the NFC device on the AP reads an NFC tag with a MIME media type
"application/vnd.wfa.wsc", the NDEF message payload (with or without
NDEF encapsulation) can be delivered to hostapd using the
following hostapd_cli command:
wps_nfc_tag_read <hexdump of payload>
If the NFC tag contains a password token, the token is added to the
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.

File diff suppressed because it is too large Load Diff

View File

@ -2,19 +2,16 @@
* hostapd / Configuration file parser
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
struct hostapd_config * hostapd_config_read(const char *fname);
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, char *field,
char *value);
#endif /* CONFIG_FILE_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,8 @@
* hostapd / UNIX domain socket -based control interface
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef CTRL_IFACE_H
@ -18,6 +12,8 @@
#ifndef CONFIG_NO_CTRL_IFACE
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
@ -27,6 +23,17 @@ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
}
static inline int
hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
{
return 0;
}
static inline void
hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
{
}
#endif /* CONFIG_NO_CTRL_IFACE */
#endif /* CTRL_IFACE_H */

View File

@ -20,13 +20,7 @@ CONFIG_DRIVER_HOSTAP=y
#CFLAGS += -I../../madwifi # change to the madwifi source directory
# Driver interface for drivers using the nl80211 kernel interface
#CONFIG_DRIVER_NL80211=y
# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
# shipped with your distribution yet. If that is the case, you need to build
# newer libnl version and point the hostapd build to use it.
#LIBNL=/usr/src/libnl
#CFLAGS += -I$(LIBNL)/include
#LIBS += -L$(LIBNL)/lib
CONFIG_DRIVER_NL80211=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
@ -90,6 +84,9 @@ CONFIG_EAP_TTLS=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-pwd for the integrated EAP server (secure authentication with a password)
#CONFIG_EAP_PWD=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
@ -107,8 +104,12 @@ CONFIG_EAP_TTLS=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable WSC 2.0 support
#CONFIG_WPS2=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# Enable WPS support with NFC config method
#CONFIG_WPS_NFC=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
@ -137,11 +138,22 @@ CONFIG_IPV6=y
# IEEE 802.11n (High Throughput) support
#CONFIG_IEEE80211N=y
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
# IEEE 802.11ac (Very High Throughput) support
#CONFIG_IEEE80211AC=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
#CONFIG_NO_STDOUT_DEBUG=y
# Add support for writing debug log to a file: -f /tmp/hostapd.log
# Disabled by default.
#CONFIG_DEBUG_FILE=y
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
@ -151,6 +163,14 @@ CONFIG_IPV6=y
# Remove support for VLANs
#CONFIG_NO_VLAN=y
# Enable support for fully dynamic VLANs. This enables hostapd to
# automatically create bridge and VLAN interfaces if necessary.
#CONFIG_FULL_DYNAMIC_VLAN=y
# Use netlink-based kernel API for VLAN operations instead of ioctl()
# Note: This requires libnl 3.1 or newer.
#CONFIG_VLAN_NETLINK=y
# Remove support for dumping state into a file on SIGUSR1 signal
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
@ -173,3 +193,77 @@ CONFIG_IPV6=y
#LIBS += -lbfd -liberty -lz
#LIBS_p += -lbfd -liberty -lz
#LIBS_c += -lbfd -liberty -lz
# hostapd depends on strong random number generation being available from the
# operating system. os_get_random() function is used to fetch random data when
# needed, e.g., for key generation. On Linux and BSD systems, this works by
# reading /dev/urandom. It should be noted that the OS entropy pool needs to be
# properly initialized before hostapd is started. This is important especially
# on embedded devices that do not have a hardware random number generator and
# may by default start up with minimal entropy available for random number
# generation.
#
# As a safety net, hostapd is by default trying to internally collect
# additional entropy for generating random data to mix in with the data
# fetched from the OS. This by itself is not considered to be very strong, but
# it may help in cases where the system pool is not initialized properly.
# However, it is very strongly recommended that the system pool is initialized
# with enough entropy either by using hardware assisted random number
# generator or by storing state over device reboots.
#
# hostapd can be configured to maintain its own entropy store over restarts to
# enhance random number generation. This is not perfect, but it is much more
# secure than using the same sequence of random numbers after every reboot.
# This can be enabled with -e<entropy file> command line option. The specified
# file needs to be readable and writable by hostapd.
#
# If the os_get_random() is known to provide strong random data (e.g., on
# Linux/BSD, the board in question is known to have reliable source of random
# data from /dev/urandom), the internal hostapd random pool can be disabled.
# This will save some in binary size and CPU use. However, this should only be
# considered for builds that are known to be used on devices that meet the
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
# internal = Internal TLSv1 implementation (experimental)
# none = Empty template
#CONFIG_TLS=openssl
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
# can be enabled to get a stronger construction of messages when block ciphers
# are used.
#CONFIG_TLSV11=y
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
# can be enabled to enable use of stronger crypto algorithms.
#CONFIG_TLSV12=y
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
# and drawbacks of this option.
#CONFIG_INTERNAL_LIBTOMMATH=y
#ifndef CONFIG_INTERNAL_LIBTOMMATH
#LTM_PATH=/usr/src/libtommath-0.39
#CFLAGS += -I$(LTM_PATH)
#LIBS += -L$(LTM_PATH)
#LIBS_p += -L$(LTM_PATH)
#endif
# At the cost of about 4 kB of additional binary size, the internal LibTomMath
# can be configured to include faster routines for exptmod, sqr, and div to
# speed up DH and RSA calculation considerably
#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks.
#CONFIG_INTERWORKING=y
# Hotspot 2.0
#CONFIG_HS20=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y

View File

@ -2,17 +2,12 @@
* hostapd / State dump
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <time.h>
#include "utils/common.h"
#include "radius/radius_client.h"
@ -106,7 +101,8 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
fprintf(f,
" AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
" AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"\n"
" capability=0x%x listen_interval=%d\n",
sta->aid,
sta->flags,
@ -115,8 +111,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
(sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" :
""),
(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
""),
(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
@ -128,6 +123,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
sta->capability,
sta->listen_interval);

View File

@ -2,14 +2,8 @@
* hostapd / State dump
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DUMP_STATE_H

View File

@ -2,14 +2,8 @@
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
@ -45,6 +39,11 @@ int eap_server_register_methods(void)
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_UNAUTH_TLS
if (ret == 0)
ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_TLS */
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
@ -130,5 +129,10 @@ int eap_server_register_methods(void)
ret = eap_server_tnc_register();
#endif /* EAP_SERVER_TNC */
#ifdef EAP_SERVER_PWD
if (ret == 0)
ret = eap_server_pwd_register();
#endif /* EAP_SERVER_PWD */
return ret;
}

View File

@ -2,14 +2,8 @@
* EAP method registration
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef EAP_REGISTER_H

View File

@ -1,15 +1,9 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
* Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*
* This is an example implementation of the EAP-SIM/AKA database/authentication
* gateway interface to HLR/AuC. It is expected to be replaced with an
@ -40,18 +34,30 @@
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
* for real life authentication, but it is useful both as an example
* implementation and for EAP-SIM testing.
* implementation and for EAP-SIM/AKA/AKA' testing.
*
* SQN generation follows the not time-based Profile 2 described in
* 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
* can be changed with a command line options if needed.
*/
#include "includes.h"
#include <sys/un.h>
#ifdef CONFIG_SQLITE
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/milenage.h"
#include "crypto/random.h"
static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
static const char *socket_path;
static int serv_sock = -1;
static char *milenage_file = NULL;
static int update_milenage = 0;
static int sqn_changes = 0;
static int ind_len = 5;
/* GSM triplets */
struct gsm_triplet {
@ -72,6 +78,7 @@ struct milenage_parameters {
u8 opc[16];
u8 amf[2];
u8 sqn[6];
int set;
};
static struct milenage_parameters *milenage_db = NULL;
@ -86,6 +93,144 @@ static struct milenage_parameters *milenage_db = NULL;
#define EAP_AKA_CK_LEN 16
#ifdef CONFIG_SQLITE
static sqlite3 *sqlite_db = NULL;
static struct milenage_parameters db_tmp_milenage;
static int db_table_exists(sqlite3 *db, const char *name)
{
char cmd[128];
os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
}
static int db_table_create_milenage(sqlite3 *db)
{
char *err = NULL;
const char *sql =
"CREATE TABLE milenage("
" imsi INTEGER PRIMARY KEY NOT NULL,"
" ki CHAR(32) NOT NULL,"
" opc CHAR(32) NOT NULL,"
" amf CHAR(4) NOT NULL,"
" sqn CHAR(12) NOT NULL"
");";
printf("Adding database table for milenage information\n");
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
printf("SQLite error: %s\n", err);
sqlite3_free(err);
return -1;
}
return 0;
}
static sqlite3 * db_open(const char *db_file)
{
sqlite3 *db;
if (sqlite3_open(db_file, &db)) {
printf("Failed to open database %s: %s\n",
db_file, sqlite3_errmsg(db));
sqlite3_close(db);
return NULL;
}
if (!db_table_exists(db, "milenage") &&
db_table_create_milenage(db) < 0) {
sqlite3_close(db);
return NULL;
}
return db;
}
static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
{
struct milenage_parameters *m = ctx;
int i;
m->set = 1;
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
printf("Invalid ki value in database\n");
return -1;
}
if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
printf("Invalid opcvalue in database\n");
return -1;
}
if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
printf("Invalid amf value in database\n");
return -1;
}
if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
printf("Invalid sqn value in database\n");
return -1;
}
}
return 0;
}
static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
{
char cmd[128];
unsigned long long imsi;
os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
imsi = atoll(imsi_txt);
os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
"%llu", imsi);
os_snprintf(cmd, sizeof(cmd),
"SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
imsi);
if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
NULL) != SQLITE_OK)
return NULL;
if (!db_tmp_milenage.set)
return NULL;
return &db_tmp_milenage;
}
static int db_update_milenage_sqn(struct milenage_parameters *m)
{
char cmd[128], val[13], *pos;
pos = val;
pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
*pos = '\0';
os_snprintf(cmd, sizeof(cmd),
"UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
val, m->imsi);
if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
printf("Failed to update SQN in database for IMSI %s\n",
m->imsi);
return -1;
}
return 0;
}
#endif /* CONFIG_SQLITE */
static int open_socket(const char *path)
{
struct sockaddr_un addr;
@ -101,7 +246,7 @@ static int open_socket(const char *path)
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind(PF_UNIX)");
perror("hlr-auc-gw: bind(PF_UNIX)");
close(s);
return -1;
}
@ -215,7 +360,7 @@ static int read_gsm_triplets(const char *fname)
gsm_db = g;
g = NULL;
}
free(g);
os_free(g);
fclose(f);
@ -365,7 +510,7 @@ static int read_milenage(const char *fname)
milenage_db = m;
m = NULL;
}
free(m);
os_free(m);
fclose(f);
@ -373,6 +518,80 @@ static int read_milenage(const char *fname)
}
static void update_milenage_file(const char *fname)
{
FILE *f, *f2;
char buf[500], *pos;
char *end = buf + sizeof(buf);
struct milenage_parameters *m;
size_t imsi_len;
f = fopen(fname, "r");
if (f == NULL) {
printf("Could not open Milenage data file '%s'\n", fname);
return;
}
snprintf(buf, sizeof(buf), "%s.new", fname);
f2 = fopen(buf, "w");
if (f2 == NULL) {
printf("Could not write Milenage data file '%s'\n", buf);
fclose(f);
return;
}
while (fgets(buf, sizeof(buf), f)) {
/* IMSI Ki OPc AMF SQN */
buf[sizeof(buf) - 1] = '\0';
pos = strchr(buf, ' ');
if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
goto no_update;
imsi_len = pos - buf;
for (m = milenage_db; m; m = m->next) {
if (strncmp(buf, m->imsi, imsi_len) == 0 &&
m->imsi[imsi_len] == '\0')
break;
}
if (!m)
goto no_update;
pos = buf;
pos += snprintf(pos, end - pos, "%s ", m->imsi);
pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
*pos++ = '\n';
no_update:
fprintf(f2, "%s", buf);
}
fclose(f2);
fclose(f);
snprintf(buf, sizeof(buf), "%s.bak", fname);
if (rename(fname, buf) < 0) {
perror("rename");
return;
}
snprintf(buf, sizeof(buf), "%s.new", fname);
if (rename(buf, fname) < 0) {
perror("rename");
return;
}
}
static struct milenage_parameters * get_milenage(const char *imsi)
{
struct milenage_parameters *m = milenage_db;
@ -383,6 +602,11 @@ static struct milenage_parameters * get_milenage(const char *imsi)
m = m->next;
}
#ifdef CONFIG_SQLITE
if (!m)
m = db_get_milenage(imsi);
#endif /* CONFIG_SQLITE */
return m;
}
@ -418,7 +642,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
if (m) {
u8 _rand[16], sres[4], kc[8];
for (count = 0; count < max_chal; count++) {
if (os_get_random(_rand, 16) < 0)
if (random_get_bytes(_rand, 16) < 0)
return;
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
*rpos++ = ' ';
@ -465,6 +689,28 @@ send:
}
static void inc_sqn(u8 *sqn)
{
u64 val, seq, ind;
/*
* SQN = SEQ | IND = SEQ1 | SEQ2 | IND
*
* The mechanism used here is not time-based, so SEQ2 is void and
* SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
* of SEQ1 is 48 - ind_len bits.
*/
/* Increment both SEQ and IND by one */
val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
seq = (val >> ind_len) + 1;
ind = (val + 1) & ((1 << ind_len) - 1);
val = (seq << ind_len) | ind;
WPA_PUT_BE32(sqn, val >> 16);
WPA_PUT_BE16(sqn + 4, val & 0xffff);
}
static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
{
@ -478,13 +724,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
size_t res_len;
int ret;
struct milenage_parameters *m;
int failed = 0;
m = get_milenage(imsi);
if (m) {
if (os_get_random(_rand, EAP_AKA_RAND_LEN) < 0)
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
return;
res_len = EAP_AKA_RES_MAX_LEN;
inc_byte_array(m->sqn, 6);
inc_sqn(m->sqn);
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
m->sqn[3], m->sqn[4], m->sqn[5]);
@ -501,7 +752,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
memset(res, '2', EAP_AKA_RES_MAX_LEN);
res_len = EAP_AKA_RES_MAX_LEN;
#else /* AKA_USE_FIXED_TEST_VALUES */
return;
failed = 1;
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
@ -511,6 +762,13 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
if (ret < 0 || ret >= end - pos)
return;
pos += ret;
if (failed) {
ret = snprintf(pos, end - pos, "FAILURE");
if (ret < 0 || ret >= end - pos)
return;
pos += ret;
goto done;
}
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
@ -521,6 +779,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
done:
printf("Send: %s\n", reply);
if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
@ -568,6 +827,10 @@ static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
#ifdef CONFIG_SQLITE
db_update_milenage_sqn(m);
#endif /* CONFIG_SQLITE */
sqn_changes = 1;
}
}
@ -614,22 +877,32 @@ static void cleanup(void)
struct gsm_triplet *g, *gprev;
struct milenage_parameters *m, *prev;
if (update_milenage && milenage_file && sqn_changes)
update_milenage_file(milenage_file);
g = gsm_db;
while (g) {
gprev = g;
g = g->next;
free(gprev);
os_free(gprev);
}
m = milenage_db;
while (m) {
prev = m;
m = m->next;
free(prev);
os_free(prev);
}
close(serv_sock);
unlink(socket_path);
#ifdef CONFIG_SQLITE
if (sqlite_db) {
sqlite3_close(sqlite_db);
sqlite_db = NULL;
}
#endif /* CONFIG_SQLITE */
}
@ -644,18 +917,22 @@ static void usage(void)
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
"Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
"Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>]\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
" [-D<DB file>] [-i<IND len in bits>]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
" -u = update SQN in Milenage file on exit\n"
" -s<socket path> = path for UNIX domain socket\n"
" (default: %s)\n"
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n",
" -m<milenage file> = path for Milenage keys\n"
" -D<DB file> = path to SQLite database\n"
" -i<IND len in bits> = IND length for SQN (default: 5)\n",
default_socket_path);
}
@ -663,34 +940,65 @@ static void usage(void)
int main(int argc, char *argv[])
{
int c;
char *milenage_file = NULL;
char *gsm_triplet_file = NULL;
char *sqlite_db_file = NULL;
if (os_program_init())
return -1;
socket_path = default_socket_path;
for (;;) {
c = getopt(argc, argv, "g:hm:s:");
c = getopt(argc, argv, "D:g:hi:m:s:u");
if (c < 0)
break;
switch (c) {
case 'D':
#ifdef CONFIG_SQLITE
sqlite_db_file = optarg;
break;
#else /* CONFIG_SQLITE */
printf("No SQLite support included in the build\n");
return -1;
#endif /* CONFIG_SQLITE */
case 'g':
gsm_triplet_file = optarg;
break;
case 'h':
usage();
return 0;
case 'i':
ind_len = atoi(optarg);
if (ind_len < 0 || ind_len > 32) {
printf("Invalid IND length\n");
return -1;
}
break;
case 'm':
milenage_file = optarg;
break;
case 's':
socket_path = optarg;
break;
case 'u':
update_milenage = 1;
break;
default:
usage();
return -1;
}
}
if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
usage();
return -1;
}
#ifdef CONFIG_SQLITE
if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
return -1;
#endif /* CONFIG_SQLITE */
if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
return -1;
@ -710,5 +1018,14 @@ int main(int argc, char *argv[])
for (;;)
process(serv_sock);
#ifdef CONFIG_SQLITE
if (sqlite_db) {
sqlite3_close(sqlite_db);
sqlite_db = NULL;
}
#endif /* CONFIG_SQLITE */
os_program_deinit();
return 0;
}

View File

@ -0,0 +1,104 @@
HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
database/authentication gateway interface to HLR/AuC. It could be
replaced with an implementation of SS7 gateway to GSM/UMTS
authentication center (HLR/AuC). hostapd will send SIM/AKA
authentication queries over a UNIX domain socket to and external
program, e.g., hlr_auc_gw.
hlr_auc_gw can be configured with GSM and UMTS authentication data with
text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
GSM triplet data is used for a more static configuration (e.g., triplets
extracted from a SIM card).
Alternatively, hlr_auc_gw can be built with support for an SQLite
database for more dynamic operations. This is enabled by adding
"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
clean; make hlr_auc_gw" in this directory).
hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
is configured with command line parameters:
hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
[-D<DB file>] [-i<IND len in bits>]
options:
-h = show this usage help
-u = update SQN in Milenage file on exit
-s<socket path> = path for UNIX domain socket
(default: /tmp/hlr_auc_gw.sock)
-g<triplet file> = path for GSM authentication triplets
-m<milenage file> = path for Milenage keys
-D<DB file> = path to SQLite database
-i<IND len in bits> = IND length for SQN (default: 5)
The SQLite database can be initialized with sqlite, e.g., by running
following commands in "sqlite3 /path/to/hlr_auc_gw.db":
CREATE TABLE milenage(
imsi INTEGER PRIMARY KEY NOT NULL,
ki CHAR(32) NOT NULL,
opc CHAR(32) NOT NULL,
amf CHAR(4) NOT NULL,
sqn CHAR(12) NOT NULL
);
INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
232010000000000,
'90dca4eda45b53cf0f12d7c9c3bc6a89',
'cb9cccc4b9258e6dca4760379fb82581',
'61df',
'000000000000'
);
INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
555444333222111,
'5122250214c33e723a5dd523fc145fc0',
'981d464c7c52eb6e5036234984ad0bcf',
'c3ab',
'16f3b3f70fc1'
);
hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
pseudonyms and reauth information into a SQLite database. This is
configured with the db parameter within the eap_sim_db configuration
option.
"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
Milenage parameters based on IMSI from the database. The database can be
updated dynamically while hlr_auc_gw is running to add/remove/modify
entries.
Example configuration files for hostapd to operate as a RADIUS
authentication server for EAP-SIM/AKA/AKA':
hostapd.conf:
driver=none
radius_server_clients=hostapd.radius_clients
eap_server=1
eap_user_file=hostapd.eap_user
eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
eap_sim_aka_result_ind=1
hostapd.radius_clients:
0.0.0.0/0 radius
hostapd.eap_user:
"0"* AKA
"1"* SIM
"2"* AKA
"3"* SIM
"4"* AKA
"5"* SIM
"6"* AKA'
"7"* AKA'
"8"* AKA'

View File

@ -84,6 +84,14 @@ ctrl_interface_group=0
# SSID to be used in IEEE 802.11 management frames
ssid=test
# Alternative formats for configuring SSID
# (double quoted string, hexdump, printf-escaped string)
#ssid2="test"
#ssid2=74657374
#ssid2=P"hello\nthere"
# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
#utf8_ssid=1
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
@ -98,20 +106,21 @@ ssid=test
#ieee80211d=1
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
# specify band)
# Default: IEEE 802.11b
hw_mode=a
hw_mode=g
# Channel number (IEEE 802.11)
# (default: 0, i.e., not set)
# Please note that some drivers (e.g., madwifi) do not use this value from
# hostapd and the channel will need to be configuration separately with
# iwconfig.
channel=60
# Please note that some drivers do not use this value from hostapd and the
# channel will need to be configured separately with iwconfig.
channel=1
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
# DTIM (delivery trafic information message) period (range 1..255):
# DTIM (delivery traffic information message) period (range 1..255):
# number of beacons between DTIMs (1 = every beacon includes DTIM element)
# (default: 2)
dtim_period=2
@ -197,8 +206,14 @@ auth_algs=3
# requests for broadcast SSID
ignore_broadcast_ssid=0
# Additional vendor specfic elements for Beacon and Probe Response frames
# This parameter can be used to add additional vendor specific element(s) into
# the end of the Beacon and Probe Response frames. The format for these
# element(s) is a hexdump of the raw information elements (id+len+payload for
# one or more elements)
#vendor_elements=dd0411223301
# TX queue parameters (EDCF / bursting)
# default for all these fields: not set, use hardware defaults
# tx_queue_<queue name>_<param>
# queues: data0, data1, data2, data3, after_beacon, beacon
# (data0 is the highest priority queue)
@ -240,18 +255,6 @@ ignore_broadcast_ssid=0
#tx_queue_data0_cwmax=7
#tx_queue_data0_burst=1.5
# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
#
# Special queues; normally not user configurable
#
#tx_queue_after_beacon_aifs=2
#tx_queue_after_beacon_cwmin=15
#tx_queue_after_beacon_cwmax=1023
#tx_queue_after_beacon_burst=0
#
#tx_queue_beacon_aifs=2
#tx_queue_beacon_cwmin=3
#tx_queue_beacon_cwmax=7
#tx_queue_beacon_burst=1.5
# 802.1D Tag (= UP) to AC mappings
# WMM specifies following mapping of data frames to different ACs. This mapping
@ -353,6 +356,17 @@ wmm_ac_vo_acm=0
# the STA with a data frame.
# default: 300 (i.e., 5 minutes)
#ap_max_inactivity=300
#
# The inactivity polling can be disabled to disconnect stations based on
# inactivity timeout so that idle stations are more likely to be disconnected
# even if they are still in range of the AP. This can be done by setting
# skip_inactivity_poll to 1 (default 0).
#skip_inactivity_poll=0
# Disassociate stations based on excessive transmission failures or other
# indications of connection loss. This depends on the driver capabilities and
# may not be available with all drivers.
#disassoc_low_ack=1
# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
# remain asleep). Default: 65535 (no limit apart from field size)
@ -364,6 +378,15 @@ wmm_ac_vo_acm=0
# bridging to be used.
#wds_sta=1
# If bridge parameter is set, the WDS STA interface will be added to the same
# bridge by default. This can be overridden with the wds_bridge parameter to
# use a separate bridge.
#wds_bridge=wds-br0
# Client isolation can be used to prevent low-level bridging of frames between
# associated stations in the BSS. By default, this bridging is allowed.
#ap_isolate=1
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@ -407,6 +430,160 @@ wmm_ac_vo_acm=0
# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
# Require stations to support HT PHY (reject association if they do not)
#require_ht=1
##### IEEE 802.11ac related configuration #####################################
# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
# 0 = disabled (default)
# 1 = enabled
# Note: You will also need to enable WMM for full VHT functionality.
#ieee80211ac=1
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
# Indicates maximum MPDU length
# 0 = 3895 octets (default)
# 1 = 7991 octets
# 2 = 11454 octets
# 3 = reserved
#
# supported_chan_width: [VHT160] [VHT160-80PLUS80]
# Indicates supported Channel widths
# 0 = 160 MHz & 80+80 channel widths are not supported (default)
# 1 = 160 MHz channel width is supported
# 2 = 160 MHz & 80+80 channel widths are supported
# 3 = reserved
#
# Rx LDPC coding capability: [RXLDPC]
# Indicates support for receiving LDPC coded pkts
# 0 = Not supported (default)
# 1 = Supported
#
# Short GI for 80 MHz: [SHORT-GI-80]
# Indicates short GI support for reception of packets transmitted with TXVECTOR
# params format equal to VHT and CBW = 80Mhz
# 0 = Not supported (default)
# 1 = Supported
#
# Short GI for 160 MHz: [SHORT-GI-160]
# Indicates short GI support for reception of packets transmitted with TXVECTOR
# params format equal to VHT and CBW = 160Mhz
# 0 = Not supported (default)
# 1 = Supported
#
# Tx STBC: [TX-STBC-2BY1]
# Indicates support for the transmission of at least 2x1 STBC
# 0 = Not supported (default)
# 1 = Supported
#
# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
# Indicates support for the reception of PPDUs using STBC
# 0 = Not supported (default)
# 1 = support of one spatial stream
# 2 = support of one and two spatial streams
# 3 = support of one, two and three spatial streams
# 4 = support of one, two, three and four spatial streams
# 5,6,7 = reserved
#
# SU Beamformer Capable: [SU-BEAMFORMER]
# Indicates support for operation as a single user beamformer
# 0 = Not supported (default)
# 1 = Supported
#
# SU Beamformee Capable: [SU-BEAMFORMEE]
# Indicates support for operation as a single user beamformee
# 0 = Not supported (default)
# 1 = Supported
#
# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
# Beamformee's capability indicating the maximum number of beamformer
# antennas the beamformee can support when sending compressed beamforming
# feedback
# If SU beamformer capable, set to maximum value minus 1
# else reserved (default)
#
# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
# Beamformer's capability indicating the maximum value of the NUM_STS parameter
# in the TXVECTOR of a VHT NDP
# If SU beamformer capable, set to maximum value minus 1
# else reserved (default)
#
# MU Beamformer Capable: [MU-BEAMFORMER]
# Indicates support for operation as an MU beamformer
# 0 = Not supported or sent by Non-AP STA (default)
# 1 = Supported
#
# MU Beamformee Capable: [MU-BEAMFORMEE]
# Indicates support for operation as an MU beamformee
# 0 = Not supported or sent by AP (default)
# 1 = Supported
#
# VHT TXOP PS: [VHT-TXOP-PS]
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
# or whether or not the STA is in VHT TXOP Power Save mode
# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
# mode
# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
# mode
#
# +HTC-VHT Capable: [HTC-VHT]
# Indicates whether or not the STA supports receiving a VHT variant HT Control
# field.
# 0 = Not supported (default)
# 1 = supported
#
# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
# This field is an integer in the range of 0 to 7.
# The length defined by this field is equal to
# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
#
# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
# Indicates whether or not the STA supports link adaptation using VHT variant
# HT Control field
# If +HTC-VHTcapable is 1
# 0 = (no feedback) if the STA does not provide VHT MFB (default)
# 1 = reserved
# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
# STA provides unsolicited VHT MFB
# Reserved if +HTC-VHTcapable is 0
#
# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
# Indicates the possibility of Rx antenna pattern change
# 0 = Rx antenna pattern might change during the lifetime of an association
# 1 = Rx antenna pattern does not change during the lifetime of an association
#
# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
# Indicates the possibility of Tx antenna pattern change
# 0 = Tx antenna pattern might change during the lifetime of an association
# 1 = Tx antenna pattern does not change during the lifetime of an association
#vht_capab=[SHORT-GI-80][HTC-VHT]
#
# Require stations to support VHT PHY (reject association if they do not)
#require_vht=1
# 0 = 20 or 40 MHz operating Channel width
# 1 = 80 MHz channel width
# 2 = 160 MHz channel width
# 3 = 80+80 MHz channel width
#vht_oper_chwidth=1
#
# center freq = 5 GHz + (5 * index)
# So index 42 gives center freq 5.210 GHz
# which is channel 42 in 5G band
#
#vht_oper_centr_freq_seg0_idx=42
#
# center freq = 5 GHz + (5 * index)
# So index 159 gives center freq 5.795 GHz
# which is channel 159 in 5G band
#
#vht_oper_centr_freq_seg1_idx=159
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@ -463,6 +640,8 @@ eapol_key_index_workaround=0
eap_server=0
# Path for EAP server user database
# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
# to use SQLite database instead of a text file.
#eap_user_file=/etc/hostapd.eap_user
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
@ -504,12 +683,21 @@ eap_server=0
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
#dh_file=/etc/hostapd.dh.pem
# Fragment size for EAP methods
#fragment_size=1400
# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
# using the IANA repository for IKE (RFC 2409).
#pwd_group=19
# Configuration data for EAP-SIM database/authentication gateway interface.
# This is a text string in implementation specific format. The example
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
# prefix.
# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
# database file can be described with an optional db=<path> parameter.
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
# random value. It is configured as a 16-octet value in hex format. It can be
@ -616,6 +804,12 @@ own_ip_addr=127.0.0.1
# 60 (1 minute).
#radius_acct_interim_interval=600
# Request Chargeable-User-Identity (RFC 4372)
# This parameter can be used to configure hostapd to request CUI from the
# RADIUS server by including Chargeable-User-Identity attribute into
# Access-Request packets.
#radius_request_cui=1
# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
@ -643,6 +837,61 @@ own_ip_addr=127.0.0.1
# to the bridge.
#vlan_tagged_interface=eth0
# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
# to know how to name it.
# 0 = vlan<XXX>, e.g., vlan1
# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
#vlan_naming=0
# Arbitrary RADIUS attributes can be added into Access-Request and
# Accounting-Request packets by specifying the contents of the attributes with
# the following configuration parameters. There can be multiple of these to
# add multiple attributes. These parameters can also be used to override some
# of the attributes added automatically by hostapd.
# Format: <attr_id>[:<syntax:value>]
# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
# syntax: s = string (UTF-8), d = integer, x = octet string
# value: attribute value in format indicated by the syntax
# If syntax and value parts are omitted, a null value (single 0x00 octet) is
# used.
#
# Additional Access-Request attributes
# radius_auth_req_attr=<attr_id>[:<syntax:value>]
# Examples:
# Operator-Name = "Operator"
#radius_auth_req_attr=126:s:Operator
# Service-Type = Framed (2)
#radius_auth_req_attr=6:d:2
# Connect-Info = "testing" (this overrides the automatically generated value)
#radius_auth_req_attr=77:s:testing
# Same Connect-Info value set as a hexdump
#radius_auth_req_attr=77:x:74657374696e67
#
# Additional Accounting-Request attributes
# radius_acct_req_attr=<attr_id>[:<syntax:value>]
# Examples:
# Operator-Name = "Operator"
#radius_acct_req_attr=126:s:Operator
# Dynamic Authorization Extensions (RFC 5176)
# This mechanism can be used to allow dynamic changes to user session based on
# commands from a RADIUS server (or some other disconnect client that has the
# needed session information). For example, Disconnect message can be used to
# request an associated station to be disconnected.
#
# This is disabled by default. Set radius_das_port to non-zero UDP port
# number to enable.
#radius_das_port=3799
#
# DAS client (the host that can send Disconnect/CoA requests) and shared secret
#radius_das_client=192.168.1.123 shared secret here
#
# DAS Event-Timestamp time window in seconds
#radius_das_time_window=300
#
# DAS require Event-Timestamp
#radius_das_require_event_timestamp=1
##### RADIUS authentication server configuration ##############################
@ -666,6 +915,7 @@ own_ip_addr=127.0.0.1
# Enable WPA. Setting this variable configures the AP to require WPA (either
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
# RADIUS authentication server must be configured, and WPA-EAP must be included
# in wpa_key_mgmt.
@ -690,6 +940,15 @@ own_ip_addr=127.0.0.1
# configuration reloads.
#wpa_psk_file=/etc/hostapd.wpa_psk
# Optionally, WPA passphrase can be received from RADIUS authentication server
# This requires macaddr_acl to be set to 2 (RADIUS)
# 0 = disabled (default)
# 1 = optional; use default passphrase/psk if RADIUS server does not include
# Tunnel-Password
# 2 = required; reject authentication if RADIUS server does not include
# Tunnel-Password
#wpa_psk_radius=0
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
@ -763,6 +1022,13 @@ own_ip_addr=127.0.0.1
# dot11AssociationSAQueryRetryTimeout, 1...4294967295
#assoc_sa_query_retry_timeout=201
# disable_pmksa_caching: Disable PMKSA caching
# This parameter can be used to disable caching of PMKSA created through EAP
# authentication. RSN preauthentication may still end up using PMKSA caching if
# it is enabled (rsn_preauth=1).
# 0 = PMKSA caching enabled (default)
# 1 = PMKSA caching disabled
#disable_pmksa_caching=0
# okc: Opportunistic Key Caching (aka Proactive Key Caching)
# Allow PMK cache to be shared opportunistically among configured interfaces
@ -910,8 +1176,21 @@ own_ip_addr=127.0.0.1
# Config Methods
# List of the supported configuration methods
# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
# nfc_interface push_button keypad
#config_methods=label display push_button keypad
# nfc_interface push_button keypad virtual_display physical_display
# virtual_push_button physical_push_button
#config_methods=label virtual_display virtual_push_button keypad
# WPS capability discovery workaround for PBC with Windows 7
# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
# as a Registrar and using M1 from the AP. The config methods attribute in that
# message is supposed to indicate only the configuration method supported by
# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
# PBC shall not be used and as such, the PushButton config method is removed
# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
# the PushButton config method is left in M1 (if included in config_methods
# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
# in the AP).
#pbc_in_m1=1
# Static access point PIN for initial configuration and adding Registrars
# If not set, hostapd will not allow external WPS Registrars to control the
@ -981,6 +1260,246 @@ own_ip_addr=127.0.0.1
# 12-digit, all-numeric code that identifies the consumer package.
#upc=123456789012
# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
# This value should be set according to RF band(s) supported by the AP if
# hw_mode is not set. For dual band dual concurrent devices, this needs to be
# set to ag to allow both RF bands to be advertized.
#wps_rf_bands=ag
# NFC password token for WPS
# These parameters can be used to configure a fixed NFC password token for the
# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
# these parameters are used, the AP is assumed to be deployed with a NFC tag
# that includes the matching NFC password token (e.g., written based on the
# NDEF record from nfc_pw_token).
#
#wps_nfc_dev_pw_id: Device Password ID (16..65535)
#wps_nfc_dh_pubkey: Hexdump of DH Public Key
#wps_nfc_dh_privkey: Hexdump of DH Private Key
#wps_nfc_dev_pw: Hexdump of Device Password
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
#manage_p2p=1
# Allow cross connection
#allow_cross_connection=1
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
#tdls_prohibit=1
# Prohibit use of TDLS Channel Switching in this BSS
#tdls_prohibit_chan_switch=1
##### IEEE 802.11v-2011 #######################################################
# Time advertisement
# 0 = disabled (default)
# 2 = UTC time at which the TSF timer is 0
#time_advertisement=2
# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
# stdoffset[dst[offset][,start[/time],end[/time]]]
#time_zone=EST5
# WNM-Sleep Mode (extended sleep mode for stations)
# 0 = disabled (default)
# 1 = enabled (allow stations to use WNM-Sleep Mode)
#wnm_sleep_mode=1
# BSS Transition Management
# 0 = disabled (default)
# 1 = enabled
#bss_transition=1
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
#interworking=1
# Access Network Type
# 0 = Private network
# 1 = Private network with guest access
# 2 = Chargeable public network
# 3 = Free public network
# 4 = Personal device network
# 5 = Emergency services only network
# 14 = Test or experimental
# 15 = Wildcard
#access_network_type=0
# Whether the network provides connectivity to the Internet
# 0 = Unspecified
# 1 = Network provides connectivity to the Internet
#internet=1
# Additional Step Required for Access
# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
# RSN is used.
#asra=0
# Emergency services reachable
#esr=0
# Unauthenticated emergency service accessible
#uesa=0
# Venue Info (optional)
# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
# Example values (group,type):
# 0,0 = Unspecified
# 1,7 = Convention Center
# 1,13 = Coffee Shop
# 2,0 = Unspecified Business
# 7,1 Private Residence
#venue_group=7
#venue_type=1
# Homogeneous ESS identifier (optional; dot11HESSID)
# If set, this shall be identifical to one of the BSSIDs in the homogeneous
# ESS and this shall be set to the same value across all BSSs in homogeneous
# ESS.
#hessid=02:03:04:05:06:07
# Roaming Consortium List
# Arbitrary number of Roaming Consortium OIs can be configured with each line
# adding a new OI to the list. The first three entries are available through
# Beacon and Probe Response frames. Any additional entry will be available only
# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
# a hexstring.
#roaming_consortium=021122
#roaming_consortium=2233445566
# Venue Name information
# This parameter can be used to configure one or more Venue Name Duples for
# Venue Name ANQP information. Each entry has a two or three character language
# code (ISO-639) separated by colon from the venue name string.
# Note that venue_group and venue_type have to be set for Venue Name
# information to be complete.
#venue_name=eng:Example venue
#venue_name=fin:Esimerkkipaikka
# Network Authentication Type
# This parameter indicates what type of network authentication is used in the
# network.
# format: <network auth type indicator (1-octet hex str)> [redirect URL]
# Network Authentication Type Indicator values:
# 00 = Acceptance of terms and conditions
# 01 = On-line enrollment supported
# 02 = http/https redirection
# 03 = DNS redirection
#network_auth_type=00
#network_auth_type=02http://www.example.com/redirect/me/here/
# IP Address Type Availability
# format: <1-octet encoded value as hex str>
# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
# ipv4_type:
# 0 = Address type not available
# 1 = Public IPv4 address available
# 2 = Port-restricted IPv4 address available
# 3 = Single NATed private IPv4 address available
# 4 = Double NATed private IPv4 address available
# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
# 7 = Availability of the address type is not known
# ipv6_type:
# 0 = Address type not available
# 1 = Address type available
# 2 = Availability of the address type not known
#ipaddr_type_availability=14
# Domain Name
# format: <variable-octet str>[,<variable-octet str>]
#domain_name=example.com,another.example.com,yet-another.example.com
# 3GPP Cellular Network information
# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
#anqp_3gpp_cell_net=244,91;310,026;234,56
# NAI Realm information
# One or more realm can be advertised. Each nai_realm line adds a new realm to
# the set. These parameters provide information for stations using Interworking
# network selection to allow automatic connection to a network based on
# credentials.
# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
# encoding:
# 0 = Realm formatted in accordance with IETF RFC 4282
# 1 = UTF-8 formatted character string that is not formatted in
# accordance with IETF RFC 4282
# NAI Realm(s): Semi-colon delimited NAI Realm(s)
# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
# ID 2 = Non-EAP Inner Authentication Type
# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
# ID 3 = Inner authentication EAP Method Type
# ID 5 = Credential Type
# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
# 10 = Vendor Specific
#nai_realm=0,example.com;example.net
# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
# username/password
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
##### Hotspot 2.0 #############################################################
# Enable Hotspot 2.0 support
#hs20=1
# Disable Downstream Group-Addressed Forwarding (DGAF)
# This can be used to configure a network where no group-addressed frames are
# allowed. The AP will not forward any group-address frames to the stations and
# random GTKs are issued for each station to prevent associated stations from
# forging such frames to other stations in the BSS.
#disable_dgaf=1
# Operator Friendly Name
# This parameter can be used to configure one or more Operator Friendly Name
# Duples. Each entry has a two or three character language code (ISO-639)
# separated by colon from the operator friendly name string.
#hs20_oper_friendly_name=eng:Example operator
#hs20_oper_friendly_name=fin:Esimerkkioperaattori
# Connection Capability
# This can be used to advertise what type of IP traffic can be sent through the
# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
# format: <IP Protocol>:<Port Number>:<Status>
# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
# Port Number: 0..65535
# Status: 0 = Closed, 1 = Open, 2 = Unknown
# Each hs20_conn_capab line is added to the list of advertised tuples.
#hs20_conn_capab=1:0:2
#hs20_conn_capab=6:22:1
#hs20_conn_capab=17:5060:0
# WAN Metrics
# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
# (encoded as two hex digits)
# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
# 1..4294967295; 0 = unknown
# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
# 1..4294967295; 0 = unknown
# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
# Load Measurement Duration: Duration for measuring downlink/uplink load in
# tenths of a second (1..65535); 0 if load cannot be determined
#hs20_wan_metrics=01:8000:1000:80:240:3000
# Operating Class Indication
# List of operating classes the BSSes in this ESS use. The Global operating
# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
# can be used in this.
# format: hexdump of operating class octets
# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
# channels 36-48):
#hs20_operating_class=5173
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN

View File

@ -69,6 +69,9 @@
"3"* SIM,TTLS,TLS,PEAP,AKA
"4"* AKA,TTLS,TLS,PEAP,SIM
"5"* SIM,TTLS,TLS,PEAP,AKA
"6"* AKA'
"7"* AKA'
"8"* AKA'
# Wildcard for all other identities
* PEAP,TTLS,TLS,SIM,AKA
@ -89,3 +92,6 @@
"3"* SIM [2]
"4"* AKA [2]
"5"* SIM [2]
"6"* AKA' [2]
"7"* AKA' [2]
"8"* AKA' [2]

View File

@ -0,0 +1,17 @@
CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
phase2 INTEGER
);
CREATE TABLE wildcards(
identity TEXT PRIMARY KEY,
methods TEXT
);
INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');

View File

@ -1,53 +1,32 @@
/*
* hostapd - command line interface for hostapd daemon
* Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <dirent.h>
#include "common/wpa_ctrl.h"
#include "common.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
"Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi> and contributors";
"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
"This program is free software. You can distribute it and/or modify it\n"
"under the terms of the GNU General Public License version 2.\n"
"\n"
"Alternatively, this software may be distributed under the terms of the\n"
"BSD license. See README and COPYING for more details.\n";
"This software may be distributed under the terms of the BSD license.\n"
"See README for more details.\n";
static const char *hostapd_cli_full_license =
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License version 2 as\n"
"published by the Free Software Foundation.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
"\n"
"Alternatively, this software may be distributed under the terms of the\n"
"BSD license.\n"
"This software may be distributed under the terms of the BSD license.\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions are\n"
@ -89,13 +68,19 @@ static const char *commands_help =
" sa_query <addr> send SA Query to a station\n"
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
" wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
" wps_check_pin <PIN> verify PIN checksum\n"
" wps_pbc indicate button pushed to initiate PBC\n"
#ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
#endif /* CONFIG_WPS_OOB */
" wps_cancel cancel the pending WPS operation\n"
#ifdef CONFIG_WPS_NFC
" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
#endif /* CONFIG_WPS_NFC */
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
" wps_config <SSID> <auth> <encr> <key> configure AP\n"
#endif /* CONFIG_WPS */
" get_config show current configuration\n"
" help show this usage help\n"
" interface [ifname] show interfaces/select interface\n"
" level <debug level> change debug level\n"
@ -110,6 +95,7 @@ static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
static void usage(void)
@ -218,6 +204,12 @@ static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "RELOG");
}
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "MIB");
@ -352,13 +344,16 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
char buf[256];
if (argc < 2) {
printf("Invalid 'wps_pin' command - at least two arguments, "
"UUID and PIN, are required.\n");
return -1;
}
if (argc > 2)
if (argc > 3)
snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
argv[0], argv[1], argv[2], argv[3]);
else if (argc > 2)
snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
argv[0], argv[1], argv[2]);
else
@ -367,6 +362,32 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
if (argc != 1 && argc != 2) {
printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
"- PIN to be verified\n");
return -1;
}
if (argc == 2)
res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
argv[0], argv[1]);
else
res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_CHECK_PIN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@ -374,38 +395,82 @@ static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
}
#ifdef CONFIG_WPS_OOB
static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
char *argv[])
static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
return wpa_ctrl_command(ctrl, "WPS_CANCEL");
}
if (argc != 3 && argc != 4) {
printf("Invalid WPS_OOB command: need three or four "
"arguments:\n"
"- DEV_TYPE: use 'ufd' or 'nfc'\n"
"- PATH: path of OOB device like '/mnt'\n"
"- METHOD: OOB method 'pin-e' or 'pin-r', "
"'cred'\n"
"- DEV_NAME: (only for NFC) device name like "
"'pn531'\n");
#ifdef CONFIG_WPS_NFC
static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
int ret;
char *buf;
size_t buflen;
if (argc != 1) {
printf("Invalid 'wps_nfc_tag_read' command - one argument "
"is required.\n");
return -1;
}
if (argc == 3)
res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
argv[0], argv[1], argv[2]);
else
res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
argv[0], argv[1], argv[2], argv[3]);
buflen = 18 + os_strlen(argv[0]);
buf = os_malloc(buflen);
if (buf == NULL)
return -1;
os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
ret = wpa_ctrl_command(ctrl, buf);
os_free(buf);
return ret;
}
static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char cmd[64];
int res;
if (argc != 1) {
printf("Invalid 'wps_nfc_config_token' command - one argument "
"is required.\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_OOB command.\n");
printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
#endif /* CONFIG_WPS_OOB */
static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
char cmd[64];
int res;
if (argc != 1) {
printf("Invalid 'wps_nfc_token' command - one argument is "
"required.\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_NFC_TOKEN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
#endif /* CONFIG_WPS_NFC */
static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
@ -427,9 +492,100 @@ static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[256];
char ssid_hex[2 * 32 + 1];
char key_hex[2 * 64 + 1];
int i;
if (argc < 1) {
printf("Invalid 'wps_config' command - at least two arguments "
"are required.\n");
return -1;
}
ssid_hex[0] = '\0';
for (i = 0; i < 32; i++) {
if (argv[0][i] == '\0')
break;
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
}
key_hex[0] = '\0';
if (argc > 3) {
for (i = 0; i < 64; i++) {
if (argv[3][i] == '\0')
break;
os_snprintf(&key_hex[i * 2], 3, "%02x",
argv[3][i]);
}
}
if (argc > 3)
snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
ssid_hex, argv[1], argv[2], key_hex);
else if (argc > 2)
snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
ssid_hex, argv[1], argv[2]);
else
snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
ssid_hex, argv[1]);
return wpa_ctrl_command(ctrl, buf);
}
#endif /* CONFIG_WPS */
static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[300];
int res;
if (argc < 2) {
printf("Invalid 'disassoc_imminent' command - two arguments "
"(STA addr and Disassociation Timer) are needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
argv[0], argv[1]);
if (res < 0 || res >= (int) sizeof(buf))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[300];
int res;
if (argc < 2) {
printf("Invalid 'ess_disassoc' command - two arguments (STA "
"addr and URL) are needed\n");
return -1;
}
res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
argv[0], argv[1]);
if (res < 0 || res >= (int) sizeof(buf))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "GET_CONFIG");
}
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
char *addr, size_t addr_len)
{
@ -499,6 +655,8 @@ static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
if (interactive)
eloop_terminate();
return 0;
}
@ -567,6 +725,46 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc != 2) {
printf("Invalid SET command: needs two arguments (variable "
"name and value)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc != 1) {
printf("Invalid GET command: needs one argument (variable "
"name)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long GET command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@ -575,6 +773,7 @@ struct hostapd_cli_cmd {
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
@ -585,17 +784,27 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin },
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
#ifdef CONFIG_WPS_OOB
{ "wps_oob", hostapd_cli_cmd_wps_oob },
#endif /* CONFIG_WPS_OOB */
{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
#ifdef CONFIG_WPS_NFC
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
#endif /* CONFIG_WPS */
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
{ "interface", hostapd_cli_cmd_interface },
{ "level", hostapd_cli_cmd_level },
{ "license", hostapd_cli_cmd_license },
{ "quit", hostapd_cli_cmd_quit },
{ "set", hostapd_cli_cmd_set },
{ "get", hostapd_cli_cmd_get },
{ NULL, NULL }
};
@ -610,6 +819,11 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
while (cmd->cmd) {
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
match = cmd;
if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
/* we have an exact match */
count = 1;
break;
}
count++;
}
cmd++;
@ -661,70 +875,39 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
}
static void hostapd_cli_interactive(void)
#define max_args 10
static int tokenize_cmd(char *cmd, char *argv[])
{
const int max_args = 10;
char cmd[256], *res, *argv[max_args], *pos;
int argc;
char *pos;
int argc = 0;
printf("\nInteractive mode\n\n");
do {
hostapd_cli_recv_pending(ctrl_conn, 0, 0);
printf("> ");
alarm(ping_interval);
res = fgets(cmd, sizeof(cmd), stdin);
alarm(0);
if (res == NULL)
break;
pos = cmd;
while (*pos != '\0') {
if (*pos == '\n') {
*pos = '\0';
break;
}
pos = cmd;
for (;;) {
while (*pos == ' ')
pos++;
if (*pos == '\0')
break;
argv[argc] = pos;
argc++;
if (argc == max_args)
break;
if (*pos == '"') {
char *pos2 = os_strrchr(pos, '"');
if (pos2)
pos = pos2 + 1;
}
argc = 0;
pos = cmd;
for (;;) {
while (*pos == ' ')
pos++;
if (*pos == '\0')
break;
argv[argc] = pos;
argc++;
if (argc == max_args)
break;
while (*pos != '\0' && *pos != ' ')
pos++;
if (*pos == ' ')
*pos++ = '\0';
}
if (argc)
wpa_request(ctrl_conn, argc, argv);
} while (!hostapd_cli_quit);
while (*pos != '\0' && *pos != ' ')
pos++;
if (*pos == ' ')
*pos++ = '\0';
}
return argc;
}
static void hostapd_cli_cleanup(void)
{
hostapd_cli_close_connection();
if (pid_file)
os_daemonize_terminate(pid_file);
os_program_deinit();
}
static void hostapd_cli_terminate(int sig)
{
hostapd_cli_cleanup();
exit(0);
}
static void hostapd_cli_alarm(int sig)
static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
printf("Connection to hostapd lost - trying to reconnect\n");
@ -744,7 +927,55 @@ static void hostapd_cli_alarm(int sig)
}
if (ctrl_conn)
hostapd_cli_recv_pending(ctrl_conn, 1, 0);
alarm(ping_interval);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
}
static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
{
eloop_terminate();
}
static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
{
char *argv[max_args];
int argc;
argc = tokenize_cmd(cmd, argv);
if (argc)
wpa_request(ctrl_conn, argc, argv);
}
static void hostapd_cli_edit_eof_cb(void *ctx)
{
eloop_terminate();
}
static void hostapd_cli_interactive(void)
{
printf("\nInteractive mode\n\n");
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
NULL, NULL, NULL, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
edit_deinit(NULL, NULL);
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
}
static void hostapd_cli_cleanup(void)
{
hostapd_cli_close_connection();
if (pid_file)
os_daemonize_terminate(pid_file);
os_program_deinit();
}
@ -787,7 +1018,6 @@ static void hostapd_cli_action(struct wpa_ctrl *ctrl)
int main(int argc, char *argv[])
{
int interactive;
int warning_displayed = 0;
int c;
int daemonize = 0;
@ -835,6 +1065,9 @@ int main(int argc, char *argv[])
hostapd_cli_license);
}
if (eloop_init())
return -1;
for (;;) {
if (ctrl_ifname == NULL) {
struct dirent *dent;
@ -874,10 +1107,6 @@ int main(int argc, char *argv[])
continue;
}
signal(SIGINT, hostapd_cli_terminate);
signal(SIGTERM, hostapd_cli_terminate);
signal(SIGALRM, hostapd_cli_alarm);
if (interactive || action_file) {
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
@ -899,6 +1128,7 @@ int main(int argc, char *argv[])
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
os_free(ctrl_ifname);
eloop_destroy();
hostapd_cli_cleanup();
return 0;
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / main()
* Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -19,6 +13,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
#include "drivers/driver.h"
@ -26,6 +21,7 @@
#include "eap_server/tncs.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
#include "config_file.h"
#include "eap_register.h"
#include "dump_state.h"
@ -36,28 +32,15 @@ extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
extern struct wpa_driver_ops *wpa_drivers[];
struct hapd_interfaces {
size_t count;
struct hostapd_iface **iface;
struct hapd_global {
void **drv_priv;
size_t drv_count;
};
static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx)
{
size_t i;
int ret;
for (i = 0; i < interfaces->count; i++) {
ret = cb(interfaces->iface[i], ctx);
if (ret)
return ret;
}
return 0;
}
static struct hapd_global global;
#ifndef CONFIG_NO_HOSTAPD_LOGGER
@ -183,14 +166,9 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
if (hapd_iface == NULL)
goto fail;
hapd_iface->reload_config = hostapd_reload_config;
hapd_iface->config_read_cb = hostapd_config_read;
hapd_iface->config_fname = os_strdup(config_file);
if (hapd_iface->config_fname == NULL)
goto fail;
hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
hapd_iface->for_each_interface = hostapd_for_each_interface;
conf = hostapd_config_read(hapd_iface->config_fname);
if (conf == NULL)
@ -198,7 +176,7 @@ static struct hostapd_iface * hostapd_init(const char *config_file)
hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss;
hapd_iface->bss = os_zalloc(conf->num_bss *
hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
goto fail;
@ -233,6 +211,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
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");
@ -244,15 +223,33 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
b = NULL;
os_memset(&params, 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.ssid = (const u8 *) hapd->conf->ssid.ssid;
params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.test_socket = hapd->conf->test_socket;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
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++) {
@ -272,25 +269,16 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
return -1;
}
if (hapd->driver->get_capa &&
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
iface->drv_flags = capa.flags;
iface->probe_resp_offloads = capa.probe_resp_offloads;
}
return 0;
}
static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
const struct wpa_driver_ops *driver;
void *drv_priv;
if (iface == NULL)
return;
driver = iface->bss[0]->driver;
drv_priv = iface->bss[0]->drv_priv;
hostapd_interface_deinit(iface);
if (driver && driver->hapd_deinit)
driver->hapd_deinit(drv_priv);
hostapd_interface_free(iface);
}
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@ -309,10 +297,13 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
iface->bss[0]->conf->logger_stdout_level--;
}
if (hostapd_driver_init(iface) ||
hostapd_setup_interface(iface)) {
hostapd_interface_deinit_free(iface);
return NULL;
if (iface->conf->bss[0].iface[0] != 0 ||
hostapd_drv_none(iface->bss[0])) {
if (hostapd_driver_init(iface) ||
hostapd_setup_interface(iface)) {
hostapd_interface_deinit_free(iface);
return NULL;
}
}
return iface;
@ -363,8 +354,13 @@ static void handle_dump_state(int sig, void *signal_ctx)
#endif /* CONFIG_NATIVE_WINDOWS */
static int hostapd_global_init(struct hapd_interfaces *interfaces)
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()) {
@ -377,6 +373,8 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
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);
@ -387,16 +385,38 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
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
@ -448,7 +468,7 @@ static void show_version(void)
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> "
"Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@ -458,15 +478,21 @@ static void usage(void)
show_version();
fprintf(stderr,
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] "
"<configuration file(s)>\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
" [-g <global ctrl_iface>] <configuration file(s)>\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"
" -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 */
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@ -474,6 +500,37 @@ static void usage(void)
}
static const char * hostapd_msg_ifname_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
if (hapd && hapd->iconf && hapd->iconf->bss)
return hapd->iconf->bss->iface;
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) {
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
return -1;
}
*pos = '\0';
interfaces->global_iface_name = pos + 1;
return 0;
}
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@ -481,12 +538,25 @@ int main(int argc, char *argv[])
size_t i;
int c, debug = 0, daemonize = 0;
char *pid_file = NULL;
const char *log_file = NULL;
const char *entropy_file = NULL;
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;
for (;;) {
c = getopt(argc, argv, "BdhKP:tv");
c = getopt(argc, argv, "Bde:f:hKP:tvg:");
if (c < 0)
break;
switch (c) {
@ -501,6 +571,12 @@ int main(int argc, char *argv[])
case 'B':
daemonize++;
break;
case 'e':
entropy_file = optarg;
break;
case 'f':
log_file = optarg;
break;
case 'K':
wpa_debug_show_keys++;
break;
@ -515,6 +591,9 @@ int main(int argc, char *argv[])
show_version();
exit(1);
break;
case 'g':
hostapd_get_global_ctrl_iface(&interfaces, optarg);
break;
default:
usage();
@ -522,18 +601,25 @@ int main(int argc, char *argv[])
}
}
if (optind == argc)
if (optind == argc && interfaces.global_iface_path == NULL)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
if (log_file)
wpa_debug_open_file(log_file);
interfaces.count = argc - optind;
interfaces.iface = os_malloc(interfaces.count *
sizeof(struct hostapd_iface *));
if (interfaces.iface == NULL) {
wpa_printf(MSG_ERROR, "malloc failed\n");
return -1;
if (interfaces.count) {
interfaces.iface = os_calloc(interfaces.count,
sizeof(struct hostapd_iface *));
if (interfaces.iface == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
return -1;
}
}
if (hostapd_global_init(&interfaces))
if (hostapd_global_init(&interfaces, entropy_file))
return -1;
/* Initialize interfaces */
@ -545,12 +631,15 @@ int main(int argc, char *argv[])
goto out;
}
hostapd_global_ctrl_iface_init(&interfaces);
if (hostapd_global_run(&interfaces, daemonize, pid_file))
goto out;
ret = 0;
out:
hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++)
hostapd_interface_deinit_free(interfaces.iface[i]);
@ -559,6 +648,9 @@ int main(int argc, char *argv[])
hostapd_global_deinit(pid_file);
os_free(pid_file);
if (log_file)
wpa_debug_close_file();
os_program_deinit();
return ret;

View File

@ -2,14 +2,8 @@
* hostapd - Plaintext password to NtPasswordHash
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"

View File

@ -0,0 +1,396 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8x does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
--- openssl-0.9.8x.orig/ssl/s3_clnt.c 2011-12-26 21:38:28.000000000 +0200
+++ openssl-0.9.8x/ssl/s3_clnt.c 2012-07-07 10:46:31.501140621 +0300
@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher=pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s)
{
int ok;
long n;
- /* If we have no ticket or session ID is non-zero length (a match of
- * a non-zero session length would never reach here) it cannot be a
- * resumed session.
- */
- if (!s->session->tlsext_tick || s->session->session_id_length)
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
return 1;
/* this function is called when we really expect a Certificate
* message, so permit appropriate message length */
diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
--- openssl-0.9.8x.orig/ssl/s3_srvr.c 2012-02-16 17:21:17.000000000 +0200
+++ openssl-0.9.8x/ssl/s3_srvr.c 2012-07-07 10:46:31.501140621 +0300
@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time=(unsigned long)time(NULL); /* Time */
+ pos=s->s3->server_random;
+ l2n(Time,pos);
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/* Worst case, we will use the NULL compression, but if we have other
* options, we will now look for them. We have i-1 compression
@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
- unsigned long l,Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p);
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d=p= &(buf[4]);
diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
--- openssl-0.9.8x.orig/ssl/ssl_err.c 2012-03-12 16:50:55.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl_err.c 2012-07-07 10:46:31.501140621 +0300
@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
{0,NULL}
};
diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
--- openssl-0.9.8x.orig/ssl/ssl.h 2012-03-12 16:50:55.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl.h 2012-07-07 10:46:31.501140621 +0300
@@ -344,6 +344,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
DECLARE_STACK_OF(SSL_CIPHER)
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -1050,6 +1054,18 @@ struct ssl_st
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
+
+ /* TLS Session Ticket extension override */
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+ /* TLS Session Ticket extension callback */
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
+ void *tls_session_ticket_ext_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
#define session_ctx initial_ctx
#else
@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
--- openssl-0.9.8x.orig/ssl/ssl_sess.c 2010-02-01 18:48:40.000000000 +0200
+++ openssl-0.9.8x/ssl/ssl_sess.c 2012-07-07 10:46:31.501140621 +0300
@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+ {
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+ }
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg)
+ {
+ if (s == NULL) return(0);
+ s->tls_session_ticket_ext_cb = cb;
+ s->tls_session_ticket_ext_cb_arg = arg;
+ return(1);
+ }
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+ {
+ if (s->version >= TLS1_VERSION)
+ {
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ s->tlsext_session_ticket = NULL;
+ }
+
+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+ if (!s->tlsext_session_ticket)
+ {
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (ext_data)
+ {
+ s->tlsext_session_ticket->length = ext_len;
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
+ }
+ else
+ {
+ s->tlsext_session_ticket->length = 0;
+ s->tlsext_session_ticket->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
--- openssl-0.9.8x.orig/ssl/t1_lib.c 2012-01-04 16:25:10.000000000 +0200
+++ openssl-0.9.8x/ssl/t1_lib.c 2012-07-07 10:47:31.153140501 +0300
@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket)
+ {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif
ssl3_free(s);
}
@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (!s->new_session && s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data)
+ {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ }
else
ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
+ skip_ext:
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
s->version != DTLS1_VERSION)
@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
return 0;
renegotiate_seen = 1;
}
+ else if (type == TLSEXT_TYPE_session_ticket)
+ {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
{
@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
}
else if (type == TLSEXT_TYPE_session_ticket)
{
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0))
{
@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
return tls_decrypt_ticket(s, p, size, session_id, len,
ret);
}
diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
--- openssl-0.9.8x.orig/ssl/tls1.h 2009-11-08 16:51:54.000000000 +0200
+++ openssl-0.9.8x/ssl/tls1.h 2012-07-07 10:46:31.501140621 +0300
@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_session_ticket_ext_st
+ {
+ unsigned short length;
+ void *data;
+ };
+
#ifdef __cplusplus
}
#endif
diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num
--- openssl-0.9.8x.orig/util/ssleay.num 2008-06-05 13:57:21.000000000 +0300
+++ openssl-0.9.8x/util/ssleay.num 2012-07-07 10:46:31.505140623 +0300
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT

View File

@ -1,4 +1,4 @@
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done

View File

@ -1,15 +1,9 @@
/*
* hostapd / RADIUS Accounting
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -23,6 +17,7 @@
#include "ieee802_1x.h"
#include "ap_config.h"
#include "sta_info.h"
#include "ap_drv_ops.h"
#include "accounting.h"
@ -31,8 +26,8 @@
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta);
static void accounting_sta_interim(struct hostapd_data *hapd,
struct sta_info *sta);
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
@ -44,6 +39,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
u8 *val;
size_t len;
int i;
struct wpabuf *b;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@ -72,7 +68,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
RADIUS_ATTR_ACCT_AUTHENTIC) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
@ -81,7 +79,17 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
}
if (sta) {
/* Use 802.1X identity if available */
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
/* Use RADIUS ACL identity if 802.1X provides no identity */
if (!val && sta->identity) {
val = (u8 *) sta->identity;
len = os_strlen(sta->identity);
}
/* Use STA MAC if neither 802.1X nor RADIUS ACL provided
* identity */
if (!val) {
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
MAC2STR(sta->addr));
@ -96,70 +104,11 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
}
}
if (hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
msg) < 0)
goto fail;
}
#ifdef CONFIG_IPV6
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
goto fail;
}
#endif /* CONFIG_IPV6 */
if (hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
printf("Could not add NAS-Identifier\n");
goto fail;
}
if (sta &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
}
if (sta) {
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(sta->addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
goto fail;
}
if (!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
}
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
i);
@ -172,6 +121,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
goto fail;
}
}
b = ieee802_1x_get_radius_cui(sta->eapol_sm);
if (b &&
!radius_msg_add_attr(msg,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
wpabuf_head(b), wpabuf_len(b))) {
wpa_printf(MSG_ERROR, "Could not add CUI");
goto fail;
}
if (!b && sta->radius_cui &&
!radius_msg_add_attr(msg,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
(u8 *) sta->radius_cui,
os_strlen(sta->radius_cui))) {
wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
goto fail;
}
}
return msg;
@ -186,7 +153,7 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
struct sta_info *sta,
struct hostap_sta_driver_data *data)
{
if (hapd->drv.read_sta_data(hapd, data, sta->addr))
if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
return -1;
if (sta->last_rx_bytes > data->rx_bytes)
@ -235,21 +202,22 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
struct os_time t;
int interval;
if (sta->acct_session_started)
return;
accounting_sta_get_id(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"starting accounting session %08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
time(&sta->acct_session_start);
os_get_time(&t);
sta->acct_session_start = t.sec;
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hapd->drv.sta_clear_stats(hapd, sta->addr);
hostapd_drv_sta_clear_stats(hapd, sta->addr);
if (!hapd->conf->radius->acct_server)
return;
@ -262,8 +230,9 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
hapd, sta);
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
if (msg)
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
if (msg &&
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
radius_msg_free(msg);
sta->acct_session_started = 1;
}
@ -275,6 +244,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
struct os_time now;
u32 gigawords;
if (!hapd->conf->radius->acct_server)
@ -288,8 +258,9 @@ static void accounting_sta_report(struct hostapd_data *hapd,
return;
}
os_get_time(&now);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
time(NULL) - sta->acct_session_start)) {
now.sec - sta->acct_session_start)) {
printf("Could not add Acct-Session-Time\n");
goto fail;
}
@ -344,7 +315,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
time(NULL))) {
now.sec)) {
printf("Could not add Event-Timestamp\n");
goto fail;
}
@ -359,9 +330,10 @@ static void accounting_sta_report(struct hostapd_data *hapd,
goto fail;
}
radius_client_send(hapd->radius, msg,
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
sta->addr);
if (radius_client_send(hapd->radius, msg,
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
sta->addr) < 0)
goto fail;
return;
fail:
@ -374,7 +346,8 @@ static void accounting_sta_report(struct hostapd_data *hapd,
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
static void accounting_sta_interim(struct hostapd_data *hapd,
struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
@ -401,7 +374,7 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
}
static void accounting_sta_get_id(struct hostapd_data *hapd,
void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
@ -464,7 +437,8 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
return;
}
radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
radius_msg_free(msg);
}
@ -475,9 +449,12 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
*/
int accounting_init(struct hostapd_data *hapd)
{
struct os_time now;
/* Acct-Session-Id should be unique over reboots. If reliable clock is
* not available, this could be replaced with reboot counter, etc. */
hapd->acct_session_id_hi = time(NULL);
os_get_time(&now);
hapd->acct_session_id_hi = now.sec;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))

View File

@ -2,21 +2,19 @@
* hostapd / RADIUS Accounting
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_NO_ACCOUNTING
static inline void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
{
@ -36,6 +34,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
{
}
#else /* CONFIG_NO_ACCOUNTING */
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
int accounting_init(struct hostapd_data *hapd);

View File

@ -1,15 +1,9 @@
/*
* hostapd / Configuration helper functions
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -74,6 +68,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->max_listen_interval = 65535;
bss->pwd_group = 19; /* ECC: GF(p=256) */
#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
@ -84,23 +80,44 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->pac_key_lifetime = 7 * 24 * 60 * 60;
bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
#endif /* EAP_SERVER_FAST */
/* Set to -1 as defaults depends on HT in setup */
bss->wmm_enabled = -1;
#ifdef CONFIG_IEEE80211R
bss->ft_over_ds = 1;
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
}
struct hostapd_config * hostapd_config_defaults(void)
{
#define ecw2cw(ecw) ((1 << (ecw)) - 1)
struct hostapd_config *conf;
struct hostapd_bss_config *bss;
int i;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
const struct hostapd_tx_queue_params txq_vi =
{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
const struct hostapd_tx_queue_params txq_vo =
{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
(ecw2cw(aCWmin) + 1) / 2 - 1, 15};
#undef ecw2cw
conf = os_zalloc(sizeof(*conf));
bss = os_zalloc(sizeof(*bss));
@ -129,16 +146,21 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->fragm_threshold = -1; /* user driver default: 2346 */
conf->send_probe_response = 1;
for (i = 0; i < NUM_TX_QUEUES; i++)
conf->tx_queue[i].aifs = -1; /* use hw default */
conf->wmm_ac_params[0] = ac_be;
conf->wmm_ac_params[1] = ac_bk;
conf->wmm_ac_params[2] = ac_vi;
conf->wmm_ac_params[3] = ac_vo;
conf->tx_queue[0] = txq_vo;
conf->tx_queue[1] = txq_vi;
conf->tx_queue[2] = txq_be;
conf->tx_queue[3] = txq_bk;
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
return conf;
}
@ -319,6 +341,30 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
}
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
{
for (; attr; attr = attr->next) {
if (attr->type == type)
return attr;
}
return NULL;
}
static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
{
struct hostapd_radius_attr *prev;
while (attr) {
prev = attr;
attr = attr->next;
wpabuf_free(prev->val);
os_free(prev);
}
}
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
os_free(user->identity);
@ -365,6 +411,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
user = user->next;
hostapd_config_free_eap_user(prev_user);
}
os_free(conf->eap_user_sqlite);
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
@ -375,6 +422,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
@ -389,6 +438,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
if (conf->ssid.dyn_vlan_keys) {
struct hostapd_ssid *ssid = &conf->ssid;
@ -403,6 +453,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
ssid->dyn_vlan_keys = NULL;
}
os_free(conf->time_zone);
#ifdef CONFIG_IEEE80211R
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
@ -433,7 +485,6 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->model_name);
os_free(conf->model_number);
os_free(conf->serial_number);
os_free(conf->device_type);
os_free(conf->config_methods);
os_free(conf->ap_pin);
os_free(conf->extra_cred);
@ -444,7 +495,30 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
#endif /* CONFIG_WPS */
os_free(conf->roaming_consortium);
os_free(conf->venue_name);
os_free(conf->nai_realm_data);
os_free(conf->network_auth_type);
os_free(conf->anqp_3gpp_cell_net);
os_free(conf->domain_name);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
#ifdef CONFIG_HS20
os_free(conf->hs20_oper_friendly_name);
os_free(conf->hs20_wan_metrics);
os_free(conf->hs20_connection_capability);
os_free(conf->hs20_operating_class);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
}
@ -549,57 +623,3 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
return NULL;
}
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2)
{
struct hostapd_eap_user *user = conf->eap_user;
#ifdef CONFIG_WPS
if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
static struct hostapd_eap_user wsc_enrollee;
os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
wsc_enrollee.methods[0].method = eap_server_get_type(
"WSC", &wsc_enrollee.methods[0].vendor);
return &wsc_enrollee;
}
if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
static struct hostapd_eap_user wsc_registrar;
os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
wsc_registrar.methods[0].method = eap_server_get_type(
"WSC", &wsc_registrar.methods[0].vendor);
wsc_registrar.password = (u8 *) conf->ap_pin;
wsc_registrar.password_len = conf->ap_pin ?
os_strlen(conf->ap_pin) : 0;
return &wsc_registrar;
}
#endif /* CONFIG_WPS */
while (user) {
if (!phase2 && user->identity == NULL) {
/* Wildcard match */
break;
}
if (user->phase2 == !!phase2 && user->wildcard_prefix &&
identity_len >= user->identity_len &&
os_memcmp(user->identity, identity, user->identity_len) ==
0) {
/* Wildcard prefix match */
break;
}
if (user->phase2 == !!phase2 &&
user->identity_len == identity_len &&
os_memcmp(user->identity, identity, identity_len) == 0)
break;
user = user->next;
}
return user;
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / Configuration definitions and helpers functions
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef HOSTAPD_CONFIG_H
@ -18,6 +12,8 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094
@ -53,9 +49,10 @@ typedef enum hostap_security_policy {
} secpolicy;
struct hostapd_ssid {
char ssid[HOSTAPD_MAX_SSID_LEN + 1];
u8 ssid[HOSTAPD_MAX_SSID_LEN];
size_t ssid_len;
int ssid_set;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@ -70,6 +67,10 @@ struct hostapd_ssid {
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
#define DYNAMIC_VLAN_NAMING_END 2
int vlan_naming;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@ -96,6 +97,11 @@ struct hostapd_vlan {
};
#define PMK_LEN 32
struct hostapd_sta_wpa_psk_short {
struct hostapd_sta_wpa_psk_short *next;
u8 psk[PMK_LEN];
};
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
@ -103,7 +109,6 @@ struct hostapd_wpa_psk {
u8 addr[ETH_ALEN];
};
#define EAP_USER_MAX_METHODS 8
struct hostapd_eap_user {
struct hostapd_eap_user *next;
u8 *identity;
@ -111,7 +116,7 @@ struct hostapd_eap_user {
struct {
int vendor;
u32 method;
} methods[EAP_USER_MAX_METHODS];
} methods[EAP_MAX_METHODS];
u8 *password;
size_t password_len;
int phase2;
@ -122,25 +127,52 @@ struct hostapd_eap_user {
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
struct hostapd_radius_attr {
u8 type;
struct wpabuf *val;
struct hostapd_radius_attr *next;
};
#define NUM_TX_QUEUES 8
#define NUM_TX_QUEUES 4
struct hostapd_tx_queue_params {
int aifs;
int cwmin;
int cwmax;
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
int configured;
};
struct hostapd_wmm_ac_params {
int cwmin;
int cwmax;
int aifs;
int txop_limit; /* in units of 32us */
int admission_control_mandatory;
#define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium {
u8 len;
u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
};
struct hostapd_lang_string {
u8 lang[3];
u8 name_len;
u8 name[252];
};
#define MAX_NAI_REALMS 10
#define MAX_NAI_REALMLEN 255
#define MAX_NAI_EAP_METHODS 5
#define MAX_NAI_AUTH_TYPES 4
struct hostapd_nai_realm_data {
u8 encoding;
char realm_buf[MAX_NAI_REALMLEN + 1];
char *realm[MAX_NAI_REALMS];
u8 eap_method_count;
struct hostapd_nai_realm_eap {
u8 eap_method;
u8 num_auths;
u8 auth_id[MAX_NAI_AUTH_TYPES];
u8 auth_val[MAX_NAI_AUTH_TYPES];
} eap_method[MAX_NAI_EAP_METHODS];
};
/**
* struct hostapd_bss_config - Per-BSS configuration
@ -148,6 +180,7 @@ struct hostapd_wmm_ac_params {
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@ -165,11 +198,21 @@ struct hostapd_bss_config {
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
int acct_interim_interval;
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
struct hostapd_radius_attr *radius_acct_req_attr;
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
struct hostapd_ip_addr radius_das_client_addr;
u8 *radius_das_shared_secret;
size_t radius_das_shared_secret_len;
struct hostapd_ssid ssid;
@ -198,6 +241,7 @@ struct hostapd_bss_config {
struct mac_acl_entry *deny_mac;
int num_deny_mac;
int wds_sta;
int isolate;
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
@ -211,6 +255,11 @@ struct hostapd_bss_config {
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
PSK_RADIUS_REQUIRED = 2
} wpa_psk_radius;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@ -231,6 +280,7 @@ struct hostapd_bss_config {
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
char *ctrl_interface; /* directory for UNIX domain sockets */
@ -254,6 +304,8 @@ struct hostapd_bss_config {
int pac_key_refresh_time;
int eap_sim_aka_result_ind;
int tnc;
int fragment_size;
u16 pwd_group;
char *radius_server_clients;
int radius_server_auth_port;
@ -283,6 +335,7 @@ struct hostapd_bss_config {
*/
u16 max_listen_interval;
int disable_pmksa_caching;
int okc; /* Opportunistic Key Caching */
int wps_state;
@ -295,7 +348,7 @@ struct hostapd_bss_config {
char *model_name;
char *model_number;
char *serial_number;
char *device_type;
u8 device_type[WPS_DEV_TYPE_LEN];
char *config_methods;
u8 os_version[4];
char *ap_pin;
@ -311,7 +364,97 @@ struct hostapd_bss_config {
char *model_description;
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
struct wpabuf *wps_nfc_dh_privkey;
struct wpabuf *wps_nfc_dev_pw;
#endif /* CONFIG_WPS */
int pbc_in_m1;
#define P2P_ENABLED BIT(0)
#define P2P_GROUP_OWNER BIT(1)
#define P2P_GROUP_FORMATION BIT(2)
#define P2P_MANAGE BIT(3)
#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
int p2p;
int disassoc_low_ack;
int skip_inactivity_poll;
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
int disable_11ac;
/* IEEE 802.11v */
int time_advertisement;
char *time_zone;
int wnm_sleep_mode;
int bss_transition;
/* IEEE 802.11u - Interworking */
int interworking;
int access_network_type;
int internet;
int asra;
int esr;
int uesa;
int venue_info_set;
u8 venue_group;
u8 venue_type;
u8 hessid[ETH_ALEN];
/* IEEE 802.11u - Roaming Consortium list */
unsigned int roaming_consortium_count;
struct hostapd_roaming_consortium *roaming_consortium;
/* IEEE 802.11u - Venue Name duples */
unsigned int venue_name_count;
struct hostapd_lang_string *venue_name;
/* IEEE 802.11u - Network Authentication Type */
u8 *network_auth_type;
size_t network_auth_type_len;
/* IEEE 802.11u - IP Address Type Availability */
u8 ipaddr_type_availability;
u8 ipaddr_type_configured;
/* IEEE 802.11u - 3GPP Cellular Network */
u8 *anqp_3gpp_cell_net;
size_t anqp_3gpp_cell_net_len;
/* IEEE 802.11u - Domain Name */
u8 *domain_name;
size_t domain_name_len;
unsigned int nai_realm_count;
struct hostapd_nai_realm_data *nai_realm_data;
u16 gas_comeback_delay;
int gas_frag_limit;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
unsigned int hs20_oper_friendly_name_count;
struct hostapd_lang_string *hs20_oper_friendly_name;
u8 *hs20_wan_metrics;
u8 *hs20_connection_capability;
size_t hs20_connection_capability_len;
u8 *hs20_operating_class;
u8 hs20_operating_class_len;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
};
@ -332,12 +475,6 @@ struct hostapd_config {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
} preamble;
enum {
CTS_PROTECTION_AUTOMATIC = 0,
CTS_PROTECTION_FORCE_ENABLED = 1,
CTS_PROTECTION_FORCE_DISABLED = 2,
CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
} cts_protection_type;
int *supported_rates;
int *basic_rates;
@ -371,6 +508,13 @@ struct hostapd_config {
u16 ht_capab;
int ieee80211n;
int secondary_channel;
int require_ht;
u32 vht_capab;
int ieee80211ac;
int require_vht;
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
};
@ -389,8 +533,7 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
#endif /* HOSTAPD_CONFIG_H */

View File

@ -2,14 +2,8 @@
* hostapd - Driver operations
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -17,14 +11,18 @@
#include "utils/common.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
#include "hs20.h"
#include "ap_drv_ops.h"
static int hostapd_sta_flags_to_drv(int flags)
u32 hostapd_sta_flags_to_drv(u32 flags)
{
int res = 0;
if (flags & WLAN_STA_AUTHORIZED)
@ -39,45 +37,190 @@ static int hostapd_sta_flags_to_drv(int flags)
}
static int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
struct wpabuf **beacon_ret,
struct wpabuf **proberesp_ret,
struct wpabuf **assocresp_ret)
{
struct wpabuf *beacon, *proberesp;
struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
u8 buf[200], *pos;
*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
pos = buf;
pos = hostapd_eid_time_adv(hapd, pos);
if (pos != buf) {
if (wpabuf_resize(&beacon, pos - buf) != 0)
goto fail;
wpabuf_put_data(beacon, buf, pos - buf);
}
pos = hostapd_eid_time_zone(hapd, pos);
if (pos != buf) {
if (wpabuf_resize(&proberesp, pos - buf) != 0)
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
pos = buf;
pos = hostapd_eid_ext_capab(hapd, pos);
if (pos != buf) {
if (wpabuf_resize(&assocresp, pos - buf) != 0)
goto fail;
wpabuf_put_data(assocresp, buf, pos - buf);
}
pos = hostapd_eid_interworking(hapd, pos);
pos = hostapd_eid_adv_proto(hapd, pos);
pos = hostapd_eid_roaming_consortium(hapd, pos);
if (pos != buf) {
if (wpabuf_resize(&beacon, pos - buf) != 0)
goto fail;
wpabuf_put_data(beacon, buf, pos - buf);
if (wpabuf_resize(&proberesp, pos - buf) != 0)
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
if (hapd->wps_beacon_ie) {
if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
0)
goto fail;
wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
}
if (hapd->wps_probe_resp_ie) {
if (wpabuf_resize(&proberesp,
wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
goto fail;
wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
}
#ifdef CONFIG_P2P
if (hapd->p2p_beacon_ie) {
if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
0)
goto fail;
wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
}
if (hapd->p2p_probe_resp_ie) {
if (wpabuf_resize(&proberesp,
wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
goto fail;
wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
if (wpabuf_resize(&beacon, 100) == 0) {
u8 *start, *p;
start = wpabuf_put(beacon, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(beacon, p - start);
}
if (wpabuf_resize(&proberesp, 100) == 0) {
u8 *start, *p;
start = wpabuf_put(proberesp, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(proberesp, p - start);
}
}
#endif /* CONFIG_P2P_MANAGER */
#ifdef CONFIG_WPS2
if (hapd->conf->wps_state) {
struct wpabuf *a = wps_build_assoc_resp_ie();
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
wpabuf_put_buf(assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WPS2 */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
if (wpabuf_resize(&assocresp, 100) == 0) {
u8 *start, *p;
start = wpabuf_put(assocresp, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(assocresp, p - start);
}
}
#endif /* CONFIG_P2P_MANAGER */
#ifdef CONFIG_WIFI_DISPLAY
if (hapd->p2p_group) {
struct wpabuf *a;
a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
wpabuf_put_buf(assocresp, a);
wpabuf_free(a);
}
#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_HS20
pos = buf;
pos = hostapd_eid_hs20_indication(hapd, pos);
if (pos != buf) {
if (wpabuf_resize(&beacon, pos - buf) != 0)
goto fail;
wpabuf_put_data(beacon, buf, pos - buf);
if (wpabuf_resize(&proberesp, pos - buf) != 0)
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
#endif /* CONFIG_HS20 */
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
return 0;
fail:
wpabuf_free(beacon);
wpabuf_free(proberesp);
wpabuf_free(assocresp);
return -1;
}
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp)
{
wpabuf_free(beacon);
wpabuf_free(proberesp);
wpabuf_free(assocresp);
}
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp;
int ret;
if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
return 0;
beacon = hapd->wps_beacon_ie;
proberesp = hapd->wps_probe_resp_ie;
if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
0)
return -1;
ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp);
ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
assocresp);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
return ret;
}
static int hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg,
size_t len)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
}
static int hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
return 0;
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
data_len, encrypt,
hapd->own_addr);
}
static int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
if (authorized) {
return hostapd_sta_set_flags(hapd, sta->addr,
@ -92,39 +235,7 @@ static int hostapd_set_authorized(struct hostapd_data *hapd,
}
static int hostapd_set_key(const char *ifname, struct hostapd_data *hapd,
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)
{
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
key_idx, set_tx, seq, seq_len, key,
key_len);
}
static int hostapd_read_sta_data(struct hostapd_data *hapd,
struct hostap_sta_driver_data *data,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
return -1;
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
}
static int hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
return 0;
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
static int hostapd_set_sta_flags(struct hostapd_data *hapd,
struct sta_info *sta)
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_flags, total_flags, flags_and, flags_or;
total_flags = hostapd_sta_flags_to_drv(sta->flags);
@ -140,8 +251,8 @@ static int hostapd_set_sta_flags(struct hostapd_data *hapd,
}
static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd,
const char *ifname, int enabled)
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled)
{
struct wpa_bss_params params;
os_memset(&params, 0, sizeof(params));
@ -154,166 +265,80 @@ static int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd,
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, &params);
}
static int hostapd_set_radius_acl_auth(struct hostapd_data *hapd,
const u8 *mac, int accepted,
u32 session_timeout)
{
if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
return 0;
return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
session_timeout);
}
static int hostapd_set_radius_acl_expire(struct hostapd_data *hapd,
const u8 *mac)
{
if (hapd->driver == NULL ||
hapd->driver->set_radius_acl_expire == NULL)
return 0;
return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
}
static int hostapd_set_bss_params(struct hostapd_data *hapd,
int use_protection)
{
int ret = 0;
int preamble;
#ifdef CONFIG_IEEE80211N
u8 buf[60], *ht_capab, *ht_oper, *pos;
pos = buf;
ht_capab = pos;
pos = hostapd_eid_ht_capabilities(hapd, pos);
ht_oper = pos;
pos = hostapd_eid_ht_operation(hapd, pos);
if (pos > ht_oper && ht_oper > ht_capab &&
hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
ht_oper + 2, ht_oper[1])) {
wpa_printf(MSG_ERROR, "Could not set HT capabilities "
"for kernel driver");
ret = -1;
}
#endif /* CONFIG_IEEE80211N */
if (hostapd_set_cts_protect(hapd, use_protection)) {
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
"driver");
ret = -1;
}
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
hostapd_set_short_slot_time(hapd,
hapd->iface->num_sta_no_short_slot_time
> 0 ? 0 : 1)) {
wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
"in kernel driver");
ret = -1;
}
if (hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE)
preamble = SHORT_PREAMBLE;
else
preamble = LONG_PREAMBLE;
if (hostapd_set_preamble(hapd, preamble)) {
wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
"driver");
ret = -1;
}
return ret;
}
static int hostapd_set_beacon(struct hostapd_data *hapd,
const u8 *head, size_t head_len,
const u8 *tail, size_t tail_len, int dtim_period,
int beacon_int)
{
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
return 0;
return hapd->driver->set_beacon(hapd->drv_priv,
head, head_len, tail, tail_len,
dtim_period, beacon_int);
}
static int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
{
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, NULL, NULL, NULL,
force_ifname, if_addr);
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
NULL, NULL, force_ifname, if_addr, NULL);
}
static int hostapd_vlan_if_remove(struct hostapd_data *hapd,
const char *ifname)
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
{
return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
}
static int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr,
int aid, int val)
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val)
{
const char *bridge = NULL;
if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
return 0;
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val);
if (hapd->conf->wds_bridge[0])
bridge = hapd->conf->wds_bridge;
else if (hapd->conf->bridge[0])
bridge = hapd->conf->bridge;
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
bridge);
}
static int hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int vlan_id)
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
return 0;
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
vlan_id);
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
static int hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
u16 seq, u16 status, const u8 *ie, size_t len)
{
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
return 0;
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
seq, status, ie, len);
}
static int hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr,
int reason)
int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
int reassoc, u16 status, const u8 *ie, size_t len)
{
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
reassoc, status, ie, len);
}
static int hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr,
int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
static int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab)
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
u32 flags, u8 qosinfo)
{
struct hostapd_sta_add_params params;
@ -330,52 +355,19 @@ static int hostapd_sta_add(struct hostapd_data *hapd,
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
static int hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen)
{
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
static int hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL ||
hapd->driver->hapd_set_countermeasures == NULL)
return 0;
return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
}
void hostapd_set_driver_ops(struct hostapd_driver_ops *ops)
{
ops->set_ap_wps_ie = hostapd_set_ap_wps_ie;
ops->send_mgmt_frame = hostapd_send_mgmt_frame;
ops->send_eapol = hostapd_send_eapol;
ops->set_authorized = hostapd_set_authorized;
ops->set_key = hostapd_set_key;
ops->read_sta_data = hostapd_read_sta_data;
ops->sta_clear_stats = hostapd_sta_clear_stats;
ops->set_sta_flags = hostapd_set_sta_flags;
ops->set_drv_ieee8021x = hostapd_set_drv_ieee8021x;
ops->set_radius_acl_auth = hostapd_set_radius_acl_auth;
ops->set_radius_acl_expire = hostapd_set_radius_acl_expire;
ops->set_bss_params = hostapd_set_bss_params;
ops->set_beacon = hostapd_set_beacon;
ops->vlan_if_add = hostapd_vlan_if_add;
ops->vlan_if_remove = hostapd_vlan_if_remove;
ops->set_wds_sta = hostapd_set_wds_sta;
ops->set_sta_vlan = hostapd_set_sta_vlan;
ops->get_inact_sec = hostapd_get_inact_sec;
ops->sta_deauth = hostapd_sta_deauth;
ops->sta_disassoc = hostapd_sta_disassoc;
ops->sta_add = hostapd_sta_add;
ops->sta_remove = hostapd_sta_remove;
ops->set_countermeasures = hostapd_set_countermeasures;
return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
tspec_ielen);
}
@ -414,12 +406,14 @@ int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr)
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr);
bss_ctx, drv_priv, force_ifname, if_addr,
bridge);
}
@ -502,16 +496,6 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
}
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
int *basic_rates, int mode)
{
if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
return 0;
return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
basic_rates, mode);
}
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
@ -521,30 +505,6 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country)
}
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
return 0;
return hapd->driver->set_cts_protect(hapd->drv_priv, value);
}
int hostapd_set_preamble(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
return 0;
return hapd->driver->set_preamble(hapd->drv_priv, value);
}
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
return 0;
return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
}
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
@ -555,15 +515,6 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
}
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
const u8 *mask)
{
if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
return 1;
return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
}
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags)
@ -584,19 +535,6 @@ int hostapd_driver_commit(struct hostapd_data *hapd)
}
int hostapd_set_ht_params(struct hostapd_data *hapd,
const u8 *ht_capab, size_t ht_capab_len,
const u8 *ht_oper, size_t ht_oper_len)
{
if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
ht_capab == NULL || ht_oper == NULL)
return 0;
return hapd->driver->set_ht_params(hapd->drv_priv,
ht_capab, ht_capab_len,
ht_oper, ht_oper_len);
}
int hostapd_drv_none(struct hostapd_data *hapd)
{
return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
@ -619,3 +557,78 @@ struct wpa_scan_results * hostapd_driver_get_scan_results(
return hapd->driver->get_scan_results2(hapd->drv_priv);
return NULL;
}
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration)
{
if (hapd->driver && hapd->driver->set_noa)
return hapd->driver->set_noa(hapd->drv_priv, count, start,
duration);
return -1;
}
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
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)
{
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
key_idx, set_tx, seq, seq_len, key,
key_len);
}
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
}
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
const u8 *peer, u8 *buf, u16 *buf_len)
{
if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
return 0;
return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
buf_len);
}
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
return 0;
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
hapd->own_addr, hapd->own_addr, data,
len, 0);
}

View File

@ -2,14 +2,8 @@
* hostapd - Driver operations
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef AP_DRV_OPS
@ -18,8 +12,32 @@
enum wpa_driver_if_type;
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
void hostapd_set_driver_ops(struct hostapd_driver_ops *ops);
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
struct wpabuf **beacon,
struct wpabuf **proberesp,
struct wpabuf **assocresp);
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled);
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val);
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
u32 flags, u8 qosinfo);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@ -27,7 +45,8 @@ int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr);
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
@ -41,27 +60,157 @@ int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and);
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
int *basic_rates, int mode);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
int hostapd_set_preamble(struct hostapd_data *hapd, int value);
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
const u8 *mask);
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags);
int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_set_ht_params(struct hostapd_data *hapd,
const u8 *ht_capab, size_t ht_capab_len,
const u8 *ht_oper, size_t ht_oper_len);
int hostapd_drv_none(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params);
struct wpa_scan_results * hostapd_driver_get_scan_results(
struct hostapd_data *hapd);
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration);
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
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);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len);
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
u16 seq, u16 status, const u8 *ie, size_t len);
int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
#include "drivers/driver.h"
int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
enum wnm_oper oper, const u8 *peer,
u8 *buf, u16 *buf_len);
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
if (hapd->driver == NULL ||
hapd->driver->hapd_set_countermeasures == NULL)
return 0;
return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
}
static inline int hostapd_drv_set_sta_vlan(const char *ifname,
struct hostapd_data *hapd,
const u8 *addr, int vlan_id)
{
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
return 0;
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
vlan_id);
}
static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
return 0;
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
}
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
u32 flags)
{
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
return 0;
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
data_len, encrypt,
hapd->own_addr, flags);
}
static inline int hostapd_drv_read_sta_data(
struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
return -1;
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
}
static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
return 0;
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
return 0;
return hapd->driver->set_ap(hapd->drv_priv, params);
}
static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
const u8 *mac, int accepted,
u32 session_timeout)
{
if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
return 0;
return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
session_timeout);
}
static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
const u8 *mac)
{
if (hapd->driver == NULL ||
hapd->driver->set_radius_acl_expire == NULL)
return 0;
return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
}
static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
int auth_algs)
{
if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
return 0;
return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
}
static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
const u8 *own_addr, const u8 *addr,
int qos)
{
if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
return;
hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
}
#endif /* AP_DRV_OPS */

View File

@ -4,14 +4,8 @@
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -227,6 +221,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
struct os_time now;
int new_ap = 0;
size_t len;
int set_beacon = 0;
@ -256,23 +251,9 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
ap->ssid_len = len;
}
os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
len = 0;
if (elems->supp_rates) {
len = elems->supp_rates_len;
if (len > WLAN_SUPP_RATES_MAX)
len = WLAN_SUPP_RATES_MAX;
os_memcpy(ap->supported_rates, elems->supp_rates, len);
}
if (elems->ext_supp_rates) {
int len2;
if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
len2 = WLAN_SUPP_RATES_MAX - len;
else
len2 = elems->ext_supp_rates_len;
os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
len2);
}
merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
ap->wpa = elems->wpa_ie != NULL;
@ -292,11 +273,10 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
ap->ht_support = 0;
ap->num_beacons++;
time(&ap->last_beacon);
if (fi) {
ap->ssi_signal = fi->ssi_signal;
os_get_time(&now);
ap->last_beacon = now.sec;
if (fi)
ap->datarate = fi->datarate;
}
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@ -324,14 +304,14 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(iface);
ieee802_11_update_beacons(iface);
}
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
time_t now;
struct os_time now;
struct ap_info *ap;
int set_beacon = 0;
@ -340,12 +320,12 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
if (!iface->ap_list)
return;
time(&now);
os_get_time(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
now)
now.sec)
break;
ap_free_ap(iface, ap);
@ -379,7 +359,7 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
}
if (set_beacon)
ieee802_11_set_beacons(iface);
ieee802_11_update_beacons(iface);
}

View File

@ -4,14 +4,8 @@
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef AP_LIST_H
@ -40,12 +34,11 @@ struct ap_info {
int channel;
int datarate; /* in 100 kbps */
int ssi_signal;
int ht_support;
unsigned int num_beacons; /* number of beacon frames received */
time_t last_beacon;
os_time_t last_beacon;
int already_seen; /* whether API call AP-NEW has already fetched
* information about this AP */

View File

@ -4,14 +4,8 @@
* Copyright 2003-2004, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"

View File

@ -4,14 +4,8 @@
* Copyright 2003-2004, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef MLME_H

View File

@ -2,14 +2,8 @@
* Authentication server setup
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -60,7 +54,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
struct eap_user *user)
{
const struct hostapd_eap_user *eap_user;
int i, count;
int i;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
@ -70,10 +64,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
return 0;
os_memset(user, 0, sizeof(*user));
count = EAP_USER_MAX_METHODS;
if (count > EAP_MAX_METHODS)
count = EAP_MAX_METHODS;
for (i = 0; i < count; i++) {
for (i = 0; i < EAP_MAX_METHODS; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
@ -101,7 +92,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
srv.conf_ctx = conf;
srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
@ -119,6 +110,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {

View File

@ -2,14 +2,8 @@
* Authentication server setup
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef AUTHSRV_H

View File

@ -2,7 +2,7 @@
* 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-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -22,15 +22,22 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.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"
#ifdef NEED_AP_MLME
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
@ -39,23 +46,11 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return 0;
switch (hapd->iconf->cts_protection_type) {
case CTS_PROTECTION_FORCE_ENABLED:
erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
break;
case CTS_PROTECTION_FORCE_DISABLED:
erp = 0;
break;
case CTS_PROTECTION_AUTOMATIC:
if (hapd->iface->olbc)
erp |= ERP_INFO_USE_PROTECTION;
/* continue */
case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
if (hapd->iface->num_sta_non_erp > 0) {
erp |= ERP_INFO_NON_ERP_PRESENT |
ERP_INFO_USE_PROTECTION;
}
break;
if (hapd->iface->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)
@ -178,8 +173,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
struct sta_info *sta)
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
{
const u8 *ie;
size_t ielen;
@ -193,92 +187,37 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
}
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
struct sta_info *sta,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len)
{
struct ieee80211_mgmt *resp;
struct ieee802_11_elems elems;
char *ssid;
u8 *pos, *epos;
const u8 *ie;
size_t ssid_len, ie_len;
struct sta_info *sta = NULL;
size_t buflen;
size_t i;
ie = mgmt->u.probe_req.variable;
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, ie, ie_len) > 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;
}
ssid = NULL;
ssid_len = 0;
if ((!elems.ssid || !elems.supp_rates)) {
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
"without SSID or supported rates element",
MAC2STR(mgmt->sa));
return;
}
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
}
sta = ap_get_sta(hapd, mgmt->sa);
if (elems.ssid_len == 0 ||
(elems.ssid_len == hapd->conf->ssid.ssid_len &&
os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
0)) {
ssid = hapd->conf->ssid.ssid;
ssid_len = hapd->conf->ssid.ssid_len;
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
}
if (!ssid) {
if (!(mgmt->da[0] & 0x01)) {
char ssid_txt[33];
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s'",
MAC2STR(mgmt->sa), ssid_txt);
}
return;
}
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
#define MAX_PROBERESP_LEN 768
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 */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
resp = os_zalloc(buflen);
if (resp == NULL)
return;
return NULL;
epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_PROBE_RESP);
os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
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);
@ -291,9 +230,9 @@ void handle_probe_req(struct hostapd_data *hapd,
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
pos += ssid_len;
*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);
@ -310,13 +249,27 @@ void handle_probe_req(struct hostapd_data *hapd,
pos = hostapd_eid_ext_supp_rates(hapd, pos);
/* RSN, MDIE, WPA */
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
pos = hostapd_eid_wpa(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);
#ifdef CONFIG_IEEE80211AC
pos = hostapd_eid_vht_capabilities(hapd, pos);
pos = hostapd_eid_vht_operation(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@ -328,23 +281,291 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_WPS */
if (hapd->drv.send_mgmt_frame(hapd, resp, pos - (u8 *) resp) < 0)
#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);
#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 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;
struct sta_info *sta = NULL;
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;
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;
}
#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;
}
sta = ap_get_sta(hapd, mgmt->sa);
#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 (sta)
sta->ssid_probe = &hapd->conf->ssid;
} else {
if (!(mgmt->da[0] & 0x01)) {
char ssid_txt[33];
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
MAC2STR(mgmt->sa), ssid_txt,
MAC2STR(mgmt->da),
elems.ssid_list ? " (SSID list)" : "");
}
return;
}
#ifdef CONFIG_INTERWORKING
if (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 (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 */
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
resp = hostapd_gen_probe_resp(hapd, sta, 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)
perror("handle_probe_req: send");
os_free(resp);
wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
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, NULL, 0, resp_len);
}
#endif /* NEED_AP_MLME */
void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct ieee80211_mgmt *head;
u8 *pos, *tail, *tailpos;
struct ieee80211_mgmt *head = NULL;
u8 *tail = NULL;
size_t head_len = 0, tail_len = 0;
u8 *resp = NULL;
size_t resp_len = 0;
struct wpa_driver_ap_params params;
struct wpabuf *beacon, *proberesp, *assocresp;
#ifdef NEED_AP_MLME
u16 capab_info;
size_t head_len, tail_len;
u8 *pos, *tailpos;
#endif /* NEED_AP_MLME */
hapd->beacon_set_done = 1;
#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@ -354,6 +575,12 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
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 */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@ -412,13 +639,30 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
/* RSN, MDIE, WPA */
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos, NULL);
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);
#ifdef CONFIG_IEEE80211AC
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@ -430,19 +674,104 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
}
#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);
#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;
if (hapd->drv.set_beacon(hapd, (u8 *) head, head_len,
tail, tail_len, hapd->conf->dtim_period,
hapd->iconf->beacon_int))
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
"period");
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */
os_memset(&params, 0, sizeof(params));
params.head = (u8 *) head;
params.head_len = head_len;
params.tail = tail;
params.tail_len = tail_len;
params.proberesp = resp;
params.proberesp_len = resp_len;
params.dtim_period = hapd->conf->dtim_period;
params.beacon_int = hapd->iconf->beacon_int;
params.basic_rates = hapd->iface->basic_rates;
params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
params.group_cipher = hapd->conf->wpa_group;
params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params.auth_algs = hapd->conf->auth_algs;
params.wpa_version = hapd->conf->wpa;
params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
(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;
}
hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
params.beacon_ies = beacon;
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.isolate = hapd->conf->isolate;
#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_HS20
params.disable_dgaf = hapd->conf->disable_dgaf;
#endif /* CONFIG_HS20 */
if (hostapd_drv_set_ap(hapd, &params))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
os_free(tail);
os_free(head);
hapd->drv.set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION));
os_free(resp);
}
@ -453,4 +782,14 @@ void ieee802_11_set_beacons(struct hostapd_iface *iface)
ieee802_11_set_beacon(iface->bss[i]);
}
/* only update beacons if started */
void ieee802_11_update_beacons(struct hostapd_iface *iface)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
if (iface->bss[i]->beacon_set_done)
ieee802_11_set_beacon(iface->bss[i]);
}
#endif /* CONFIG_NATIVE_WINDOWS */

View File

@ -19,18 +19,10 @@
struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal);
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
}
static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
{
}
#endif /* NEED_AP_MLME */
void ieee802_11_update_beacons(struct hostapd_iface *iface);
#endif /* BEACON_H */

View File

@ -2,26 +2,45 @@
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "wps_hostapd.h"
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
#include "ap_drv_ops.h"
static int hostapd_get_sta_conn_time(struct sta_info *sta,
char *buf, size_t buflen)
{
struct os_time now, age;
int len = 0, ret;
if (!sta->connected_time.sec)
return 0;
os_get_time(&now);
os_time_sub(&now, &sta->connected_time, &age);
ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
(unsigned int) age.sec);
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
len += ret;
return len;
}
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
@ -57,6 +76,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
buflen - len);
if (res >= 0)
len += res;
res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
if (res >= 0)
len += res;
return len;
}
@ -102,3 +128,170 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
#ifdef CONFIG_P2P_MANAGER
static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
u8 minor_reason_code, const u8 *addr)
{
struct ieee80211_mgmt *mgmt;
int ret;
u8 *pos;
if (hapd->driver->send_frame == NULL)
return -1;
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u)",
MAC2STR(addr), minor_reason_code, stype);
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
if (stype == WLAN_FC_STYPE_DEAUTH) {
mgmt->u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
} else {
mgmt->u.disassoc.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
}
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + 3 + 1;
WPA_PUT_BE24(pos, OUI_WFA);
pos += 3;
*pos++ = P2P_OUI_TYPE;
*pos++ = P2P_ATTR_MINOR_REASON_CODE;
WPA_PUT_LE16(pos, 1);
pos += 2;
*pos++ = minor_reason_code;
ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
pos - (u8 *) mgmt, 1);
os_free(mgmt);
return ret < 0 ? -1 : 0;
}
#endif /* CONFIG_P2P_MANAGER */
int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
txtaddr);
if (hwaddr_aton(txtaddr, addr))
return -1;
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
if (hapd->driver->send_frame == NULL)
return -1;
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_DEAUTH);
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
encrypt) < 0)
return -1;
return 0;
}
#ifdef CONFIG_P2P_MANAGER
pos = os_strstr(txtaddr, " p2p=");
if (pos) {
return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
atoi(pos + 5), addr);
}
#endif /* CONFIG_P2P_MANAGER */
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
return 0;
}
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
txtaddr);
if (hwaddr_aton(txtaddr, addr))
return -1;
pos = os_strstr(txtaddr, " test=");
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
if (hapd->driver->send_frame == NULL)
return -1;
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_DISASSOC);
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
encrypt) < 0)
return -1;
return 0;
}
#ifdef CONFIG_P2P_MANAGER
pos = os_strstr(txtaddr, " p2p=");
if (pos) {
return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
atoi(pos + 5), addr);
}
#endif /* CONFIG_P2P_MANAGER */
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
return 0;
}

View File

@ -2,14 +2,8 @@
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef CTRL_IFACE_AP_H
@ -21,5 +15,9 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
#endif /* CTRL_IFACE_AP_H */

View File

@ -2,14 +2,8 @@
* hostapd / Callback functions for driver wrappers
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -19,26 +13,37 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "accounting.h"
#include "tkip_countermeasures.h"
#include "iapp.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "wmm.h"
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "hw_features.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen)
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
int new_assoc, res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
#ifdef CONFIG_IEEE80211R
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
#endif /* CONFIG_IEEE80211R */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
if (addr == NULL) {
/*
@ -52,11 +57,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
"no address");
return -1;
}
random_add_randomness(addr, ETH_ALEN);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "associated");
ieee802_11_parse_elems(ie, ielen, &elems, 0);
ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
if (elems.wps_ie) {
ie = elems.wps_ie - 2;
ielen = elems.wps_ie_len + 2;
@ -79,15 +85,42 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta = ap_get_sta(hapd, addr);
if (sta) {
accounting_sta_stop(hapd, sta);
/*
* Make sure that the previously registered inactivity timer
* will not remove the STA immediately.
*/
sta->timeout_next = STA_NULLFUNC;
} else {
sta = ap_sta_add(hapd, addr);
if (sta == NULL)
if (sta == NULL) {
hostapd_drv_sta_disassoc(hapd, addr,
WLAN_REASON_DISASSOC_AP_BUSY);
return -1;
}
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
P2P_IE_VENDOR_TYPE);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
} else
sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
wpa_printf(MSG_DEBUG, "STA did not include "
"WPA/RSN IE in (Re)Association "
@ -95,15 +128,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MAYBE_WPS;
goto skip_wpa_check;
}
#endif /* CONFIG_WPS */
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
return -1;
}
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
if (wps) {
if (wps_is_20(wps)) {
wpa_printf(MSG_DEBUG, "WPS: STA "
"supports WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
wpabuf_free(wps);
}
goto skip_wpa_check;
}
#endif /* CONFIG_WPS */
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@ -114,48 +161,156 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
ie, ielen, NULL, 0);
ie, ielen,
elems.mdie, elems.mdie_len);
if (res != WPA_IE_OK) {
int resp;
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
"rejected? (res %u)", res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
if (res == WPA_INVALID_GROUP)
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_PAIRWISE)
resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_AKMP)
resp = WLAN_REASON_AKMP_NOT_VALID;
if (res == WPA_INVALID_GROUP) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
} else if (res == WPA_INVALID_PAIRWISE) {
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
} else if (res == WPA_INVALID_AKMP) {
reason = WLAN_REASON_AKMP_NOT_VALID;
status = WLAN_STATUS_AKMP_NOT_VALID;
}
#ifdef CONFIG_IEEE80211W
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
resp = WLAN_REASON_INVALID_IE;
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
}
#endif /* CONFIG_IEEE80211W */
else
resp = WLAN_REASON_INVALID_IE;
hapd->drv.sta_disassoc(hapd, sta->addr, resp);
ap_free_sta(hapd, sta);
return -1;
else {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
}
goto fail;
}
#ifdef CONFIG_IEEE80211W
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
sta->sa_query_count > 0)
ap_check_sa_query_timeout(hapd, sta);
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
(sta->auth_alg != WLAN_AUTH_FT)) {
/*
* STA has already been associated with MFP and SA
* Query timeout has not been reached. Reject the
* association attempt temporarily and start SA Query,
* if one is not pending.
*/
if (sta->sa_query_count == 0)
ap_sta_start_sa_query(hapd, sta);
#ifdef CONFIG_IEEE80211R
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
p - buf);
#endif /* CONFIG_IEEE80211R */
return 0;
}
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
if (sta->auth_alg == WLAN_AUTH_FT) {
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
req_ies_len);
if (status != WLAN_STATUS_SUCCESS) {
if (status == WLAN_STATUS_INVALID_PMKID)
reason = WLAN_REASON_INVALID_IE;
if (status == WLAN_STATUS_INVALID_MDIE)
reason = WLAN_REASON_INVALID_IE;
if (status == WLAN_STATUS_INVALID_FTIE)
reason = WLAN_REASON_INVALID_IE;
goto fail;
}
}
#endif /* CONFIG_IEEE80211R */
} 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) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
if (req_ies)
wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
WPS_IE_VENDOR_TYPE);
else
wps = NULL;
#ifdef CONFIG_WPS_STRICT
if (wps && wps_validate_assoc_req(wps) < 0) {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
wpabuf_free(wps);
goto fail;
}
#endif /* CONFIG_WPS_STRICT */
if (wps) {
sta->flags |= WLAN_STA_WPS;
if (wps_is_20(wps)) {
wpa_printf(MSG_DEBUG, "WPS: STA supports "
"WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
} else
sta->flags |= WLAN_STA_MAYBE_WPS;
wpabuf_free(wps);
#endif /* CONFIG_WPS */
}
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
#ifdef CONFIG_IEEE80211R
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
sta->auth_alg, req_ies, req_ies_len);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#else /* CONFIG_IEEE80211R */
/* Keep compiler silent about unused variables */
if (status) {
}
#endif /* CONFIG_IEEE80211R */
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);
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
#ifdef CONFIG_P2P
if (req_ies) {
p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
req_ies, req_ies_len);
}
#endif /* CONFIG_P2P */
return 0;
fail:
#ifdef CONFIG_IEEE80211R
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
return -1;
}
@ -163,6 +318,19 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
if (addr == NULL) {
/*
* This could potentially happen with unexpected event from the
* driver wrapper. This was seen at least in one case where the
* driver ended up reporting a station mode event while hostapd
* was running, so better make sure we stop processing such an
* event here.
*/
wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
"with no address");
return;
}
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@ -173,9 +341,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
return;
}
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
MAC2STR(sta->addr));
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);
@ -183,50 +350,180 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
}
#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
{
u16 fc, type, stype;
struct sta_info *sta = ap_get_sta(hapd, addr);
/*
* PS-Poll frames are 16 bytes. All other frames are
* 24 bytes or longer.
*/
if (len < 16)
return NULL;
if (!sta || !hapd->conf->disassoc_low_ack)
return;
fc = le_to_host16(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
switch (type) {
case WLAN_FC_TYPE_DATA:
if (len < 24)
return NULL;
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
case WLAN_FC_FROMDS | WLAN_FC_TODS:
case WLAN_FC_TODS:
return hdr->addr1;
case WLAN_FC_FROMDS:
return hdr->addr2;
default:
return NULL;
}
case WLAN_FC_TYPE_CTRL:
if (stype != WLAN_FC_STYPE_PSPOLL)
return NULL;
return hdr->addr1;
case WLAN_FC_TYPE_MGMT:
return hdr->addr3;
default:
return NULL;
}
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
"missing ACKs");
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
if (sta)
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
}
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset)
{
#ifdef NEED_AP_MLME
int channel;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "driver had channel switch: "
"freq=%d, ht=%d, offset=%d", freq, ht, offset);
hapd->iface->freq = freq;
channel = hostapd_hw_get_channel(hapd, freq);
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING, "driver switched to "
"bad channel!");
return;
}
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
hapd->iconf->secondary_channel = offset;
#endif /* NEED_AP_MLME */
}
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal)
{
size_t i;
int ret = 0;
if (sa == NULL || ie == NULL)
return -1;
random_add_randomness(sa, ETH_ALEN);
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
sa, da, bssid, ie, ie_len,
ssi_signal) > 0) {
ret = 1;
break;
}
}
return ret;
}
#ifdef HOSTAPD
#ifdef CONFIG_IEEE80211R
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
const u8 *bssid,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
sta = ap_get_sta(hapd, dst);
if (sta == NULL)
return;
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
sta->flags |= WLAN_STA_AUTH;
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
}
#endif /* CONFIG_IEEE80211R */
static void hostapd_notif_auth(struct hostapd_data *hapd,
struct auth_info *rx_auth)
{
struct sta_info *sta;
u16 status = WLAN_STATUS_SUCCESS;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
sta = ap_get_sta(hapd, rx_auth->peer);
if (!sta) {
sta = ap_sta_add(hapd, rx_auth->peer);
if (sta == NULL) {
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
}
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
#ifdef CONFIG_IEEE80211R
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
sta->auth_alg = WLAN_AUTH_FT;
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_DEBUG, "FT: Failed to initialize WPA "
"state machine");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
rx_auth->auth_transaction, rx_auth->ies,
rx_auth->ies_len,
hostapd_notify_auth_ft_finish, hapd);
return;
}
#endif /* CONFIG_IEEE80211R */
fail:
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
status, resp_ies, resp_ies_len);
}
static void hostapd_action_rx(struct hostapd_data *hapd,
struct rx_action *action)
{
struct sta_info *sta;
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
action->category, (int) action->len);
sta = ap_get_sta(hapd, action->sa);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return;
}
#ifdef CONFIG_IEEE80211R
if (action->category == WLAN_ACTION_FT) {
wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
__func__, (int) action->len);
wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
__func__, (int) action->len);
ieee802_11_sa_query_action(hapd, action->sa,
*(action->data + 1),
action->data + 2);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
if (action->category == WLAN_ACTION_WNM) {
wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
__func__, (int) action->len);
ieee802_11_rx_wnm_action_ap(hapd, action);
}
#endif /* CONFIG_WNM */
}
#ifdef NEED_AP_MLME
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@ -250,17 +547,14 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
const u8 *frame, size_t len)
const u8 *bssid, const u8 *addr,
int wds)
{
const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
u16 fc = le_to_host16(hdr->frame_control);
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
hapd = get_hapd_bssid(hapd->iface, bssid);
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
ieee802_11_rx_from_unknown(hapd, hdr->addr2,
(fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
(WLAN_FC_TODS | WLAN_FC_FROMDS));
ieee802_11_rx_from_unknown(hapd, addr, wds);
}
@ -303,6 +597,48 @@ static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
rx_mgmt->frame_len, &fi);
} else
ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
random_add_randomness(&fi, sizeof(fi));
}
static void hostapd_rx_action(struct hostapd_data *hapd,
struct rx_action *rx_action)
{
struct rx_mgmt rx_mgmt;
u8 *buf;
struct ieee80211_hdr *hdr;
wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
" BSSID=" MACSTR " category=%u",
MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
MAC2STR(rx_action->bssid), rx_action->category);
wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
rx_action->data, rx_action->len);
buf = os_zalloc(24 + 1 + rx_action->len);
if (buf == NULL)
return;
hdr = (struct ieee80211_hdr *) buf;
hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
if (rx_action->category == WLAN_ACTION_SA_QUERY) {
/*
* Assume frame was protected; it would have been dropped if
* not.
*/
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
}
os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
buf[24] = rx_action->category;
os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
rx_mgmt.frame = buf;
rx_mgmt.frame_len = 24 + 1 + rx_action->len;
hostapd_mgmt_rx(hapd, &rx_mgmt);
os_free(buf);
}
@ -320,23 +656,6 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
#endif /* NEED_AP_MLME */
static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
const u8 *ie, size_t ie_len)
{
size_t i;
int ret = 0;
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
sa, ie, ie_len) > 0) {
ret = 1;
break;
}
}
return ret;
}
static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
@ -362,12 +681,15 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
const u8 *data, size_t data_len)
{
struct hostapd_iface *iface = hapd->iface;
struct sta_info *sta;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
if (ap_get_sta(iface->bss[j], src)) {
hapd = iface->bss[j];
break;
if ((sta = ap_get_sta(iface->bss[j], src))) {
if (sta->flags & WLAN_STA_ASSOC) {
hapd = iface->bss[j];
break;
}
}
}
@ -379,6 +701,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct hostapd_data *hapd = ctx;
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
fc = le_to_host16(hdr->frame_control);
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
level = MSG_EXCESSIVE;
}
wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
event_to_string(event), event);
#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
case EVENT_MICHAEL_MIC_FAILURE:
@ -395,7 +734,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#endif /* CONFIG_IEEE80211R */
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd);
hostapd_wps_button_pushed(hapd, NULL);
break;
#ifdef NEED_AP_MLME
case EVENT_TX_STATUS:
@ -414,18 +753,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
}
break;
case EVENT_EAPOL_TX_STATUS:
hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
data->eapol_tx_status.data,
data->eapol_tx_status.data_len,
data->eapol_tx_status.ack);
break;
case EVENT_DRIVER_CLIENT_POLL_OK:
hostapd_client_poll_ok(hapd, data->client_poll.addr);
break;
case EVENT_RX_FROM_UNKNOWN:
hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
data->rx_from_unknown.len);
hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
data->rx_from_unknown.addr,
data->rx_from_unknown.wds);
break;
case EVENT_RX_MGMT:
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
break;
#endif /* NEED_AP_MLME */
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
break;
hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
data->rx_probe_req.da,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
data->rx_probe_req.ie_len);
data->rx_probe_req.ie_len,
data->rx_probe_req.ssi_signal);
break;
case EVENT_NEW_STA:
hostapd_event_new_sta(hapd, data->new_sta.addr);
@ -438,7 +793,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_ASSOC:
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
case EVENT_DISASSOC:
if (data)
@ -448,6 +804,30 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (data)
hostapd_notif_disassoc(hapd, data->deauth_info.addr);
break;
case EVENT_STATION_LOW_ACK:
if (!data)
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
case EVENT_RX_ACTION:
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
data->rx_action.bssid == NULL)
break;
#ifdef NEED_AP_MLME
hostapd_rx_action(hapd, &data->rx_action);
#endif /* NEED_AP_MLME */
hostapd_action_rx(hapd, &data->rx_action);
break;
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
case EVENT_CH_SWITCH:
if (!data)
break;
hostapd_event_ch_switch(hapd, data->ch_switch.freq,
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;

View File

@ -0,0 +1,270 @@
/*
* hostapd / EAP user database
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#ifdef CONFIG_SQLITE
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
#include "common.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap_methods.h"
#include "eap_server/eap.h"
#include "ap_config.h"
#include "hostapd.h"
#ifdef CONFIG_SQLITE
static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
{
char *buf, *start;
int num_methods;
buf = os_strdup(methods);
if (buf == NULL)
return;
os_memset(&user->methods, 0, sizeof(user->methods));
num_methods = 0;
start = buf;
while (*start) {
char *pos3 = os_strchr(start, ',');
if (pos3)
*pos3++ = '\0';
user->methods[num_methods].method =
eap_server_get_type(start,
&user->methods[num_methods].vendor);
if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
user->methods[num_methods].method == EAP_TYPE_NONE) {
if (os_strcmp(start, "TTLS-PAP") == 0) {
user->ttls_auth |= EAP_TTLS_AUTH_PAP;
goto skip_eap;
}
if (os_strcmp(start, "TTLS-CHAP") == 0) {
user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
goto skip_eap;
}
if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
goto skip_eap;
}
if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
goto skip_eap;
}
wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
start);
os_free(buf);
return;
}
num_methods++;
if (num_methods >= EAP_MAX_METHODS)
break;
skip_eap:
if (pos3 == NULL)
break;
start = pos3;
}
os_free(buf);
}
static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
{
struct hostapd_eap_user *user = ctx;
int i;
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "password") == 0 && argv[i]) {
os_free(user->password);
user->password_len = os_strlen(argv[i]);
user->password = (u8 *) os_strdup(argv[i]);
user->next = (void *) 1;
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
set_user_methods(user, argv[i]);
}
}
return 0;
}
static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
{
struct hostapd_eap_user *user = ctx;
int i, id = -1, methods = -1;
size_t len;
for (i = 0; i < argc; i++) {
if (os_strcmp(col[i], "identity") == 0 && argv[i])
id = i;
else if (os_strcmp(col[i], "methods") == 0 && argv[i])
methods = i;
}
if (id < 0 || methods < 0)
return 0;
len = os_strlen(argv[id]);
if (len <= user->identity_len &&
os_memcmp(argv[id], user->identity, len) == 0 &&
(user->password == NULL || len > user->password_len)) {
os_free(user->password);
user->password_len = os_strlen(argv[id]);
user->password = (u8 *) os_strdup(argv[id]);
user->next = (void *) 1;
set_user_methods(user, argv[methods]);
}
return 0;
}
static const struct hostapd_eap_user *
eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
size_t identity_len, int phase2)
{
sqlite3 *db;
struct hostapd_eap_user *user = NULL;
char id_str[256], cmd[300];
size_t i;
if (identity_len >= sizeof(id_str))
return NULL;
os_memcpy(id_str, identity, identity_len);
id_str[identity_len] = '\0';
for (i = 0; i < identity_len; i++) {
if (id_str[i] >= 'a' && id_str[i] <= 'z')
continue;
if (id_str[i] >= 'A' && id_str[i] <= 'Z')
continue;
if (id_str[i] >= '0' && id_str[i] <= '9')
continue;
if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
id_str[i] == '=' || id_str[i] == ' ')
continue;
wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
return NULL;
}
os_free(hapd->tmp_eap_user.identity);
os_free(hapd->tmp_eap_user.password);
os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
hapd->tmp_eap_user.phase2 = phase2;
hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
if (hapd->tmp_eap_user.identity == NULL)
return NULL;
os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
sqlite3_close(db);
return NULL;
}
os_snprintf(cmd, sizeof(cmd),
"SELECT password,methods FROM users WHERE "
"identity='%s' AND phase2=%d;", id_str, phase2);
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
} else if (hapd->tmp_eap_user.next)
user = &hapd->tmp_eap_user;
if (user == NULL && !phase2) {
os_snprintf(cmd, sizeof(cmd),
"SELECT identity,methods FROM wildcards;");
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
NULL) != SQLITE_OK) {
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
"operation");
} else if (hapd->tmp_eap_user.next) {
user = &hapd->tmp_eap_user;
os_free(user->identity);
user->identity = user->password;
user->identity_len = user->password_len;
user->password = NULL;
user->password_len = 0;
}
}
sqlite3_close(db);
return user;
}
#endif /* CONFIG_SQLITE */
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
size_t identity_len, int phase2)
{
const struct hostapd_bss_config *conf = hapd->conf;
struct hostapd_eap_user *user = conf->eap_user;
#ifdef CONFIG_WPS
if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
static struct hostapd_eap_user wsc_enrollee;
os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
wsc_enrollee.methods[0].method = eap_server_get_type(
"WSC", &wsc_enrollee.methods[0].vendor);
return &wsc_enrollee;
}
if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
static struct hostapd_eap_user wsc_registrar;
os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
wsc_registrar.methods[0].method = eap_server_get_type(
"WSC", &wsc_registrar.methods[0].vendor);
wsc_registrar.password = (u8 *) conf->ap_pin;
wsc_registrar.password_len = conf->ap_pin ?
os_strlen(conf->ap_pin) : 0;
return &wsc_registrar;
}
#endif /* CONFIG_WPS */
while (user) {
if (!phase2 && user->identity == NULL) {
/* Wildcard match */
break;
}
if (user->phase2 == !!phase2 && user->wildcard_prefix &&
identity_len >= user->identity_len &&
os_memcmp(user->identity, identity, user->identity_len) ==
0) {
/* Wildcard prefix match */
break;
}
if (user->phase2 == !!phase2 &&
user->identity_len == identity_len &&
os_memcmp(user->identity, identity, identity_len) == 0)
break;
user = user->next;
}
#ifdef CONFIG_SQLITE
if (user == NULL && conf->eap_user_sqlite) {
return eap_user_sqlite_get(hapd, identity, identity_len,
phase2);
}
#endif /* CONFIG_SQLITE */
return user;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef GAS_SERV_H
#define GAS_SERV_H
#define ANQP_REQ_CAPABILITY_LIST \
(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
#define ANQP_REQ_VENUE_NAME \
(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
#define ANQP_REQ_NETWORK_AUTH_TYPE \
(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
#define ANQP_REQ_ROAMING_CONSORTIUM \
(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
(1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
#define ANQP_REQ_NAI_REALM \
(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
#define ANQP_REQ_DOMAIN_NAME \
(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
#define ANQP_REQ_HS_CAPABILITY_LIST \
(0x10000 << HS20_STYPE_CAPABILITY_LIST)
#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
(0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME)
#define ANQP_REQ_WAN_METRICS \
(0x10000 << HS20_STYPE_WAN_METRICS)
#define ANQP_REQ_CONNECTION_CAPABILITY \
(0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
#define ANQP_REQ_NAI_HOME_REALM \
(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
#define ANQP_REQ_OPERATING_CLASS \
(0x10000 << HS20_STYPE_OPERATING_CLASS)
/* To account for latencies between hostapd and external ANQP processor */
#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
struct gas_dialog_info {
u8 valid;
u8 index;
struct wpabuf *sd_resp; /* Fragmented response */
u8 dialog_token;
size_t sd_resp_pos; /* Offset in sd_resp */
u8 sd_frag_id;
u16 comeback_delay;
unsigned int requested;
unsigned int received;
unsigned int all_requested;
};
struct hostapd_data;
void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
struct gas_dialog_info *dialog);
struct gas_dialog_info *
gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
u8 dialog_token);
void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
int gas_serv_init(struct hostapd_data *hapd);
void gas_serv_deinit(struct hostapd_data *hapd);
#endif /* GAS_SERV_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,34 +2,51 @@
* hostapd / Initialization and configuration
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef HOSTAPD_H
#define HOSTAPD_H
#include "common/defs.h"
#include "ap_config.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
struct hapd_interfaces;
struct hostapd_data;
struct sta_info;
struct hostap_sta_driver_data;
struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
struct hostapd_iface;
struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface);
struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
int (*for_each_interface)(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
int (*driver_init)(struct hostapd_iface *iface);
size_t count;
int global_ctrl_sock;
char *global_iface_path;
char *global_iface_name;
struct hostapd_iface **iface;
};
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
const u8 *ie, size_t ie_len, int ssi_signal);
void *ctx;
};
@ -43,59 +60,10 @@ struct hostapd_rate_data {
struct hostapd_frame_info {
u32 channel;
u32 datarate;
u32 ssi_signal;
int ssi_signal; /* dBm */
};
struct hostapd_driver_ops {
int (*set_ap_wps_ie)(struct hostapd_data *hapd);
int (*send_mgmt_frame)(struct hostapd_data *hapd, const void *msg,
size_t len);
int (*send_eapol)(struct hostapd_data *hapd, const u8 *addr,
const u8 *data, size_t data_len, int encrypt);
int (*set_authorized)(struct hostapd_data *hapd, struct sta_info *sta,
int authorized);
int (*set_key)(const char *ifname, struct hostapd_data *hapd,
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);
int (*read_sta_data)(struct hostapd_data *hapd,
struct hostap_sta_driver_data *data,
const u8 *addr);
int (*sta_clear_stats)(struct hostapd_data *hapd, const u8 *addr);
int (*set_sta_flags)(struct hostapd_data *hapd, struct sta_info *sta);
int (*set_drv_ieee8021x)(struct hostapd_data *hapd, const char *ifname,
int enabled);
int (*set_radius_acl_auth)(struct hostapd_data *hapd,
const u8 *mac, int accepted,
u32 session_timeout);
int (*set_radius_acl_expire)(struct hostapd_data *hapd,
const u8 *mac);
int (*set_bss_params)(struct hostapd_data *hapd, int use_protection);
int (*set_beacon)(struct hostapd_data *hapd,
const u8 *head, size_t head_len,
const u8 *tail, size_t tail_len, int dtim_period,
int beacon_int);
int (*vlan_if_add)(struct hostapd_data *hapd, const char *ifname);
int (*vlan_if_remove)(struct hostapd_data *hapd, const char *ifname);
int (*set_wds_sta)(struct hostapd_data *hapd, const u8 *addr, int aid,
int val);
int (*set_sta_vlan)(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int vlan_id);
int (*get_inact_sec)(struct hostapd_data *hapd, const u8 *addr);
int (*sta_deauth)(struct hostapd_data *hapd, const u8 *addr,
int reason);
int (*sta_disassoc)(struct hostapd_data *hapd, const u8 *addr,
int reason);
int (*sta_add)(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab);
int (*sta_remove)(struct hostapd_data *hapd, const u8 *addr);
int (*set_countermeasures)(struct hostapd_data *hapd, int enabled);
};
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
@ -123,15 +91,16 @@ struct hostapd_data {
const struct wpa_driver_ops *driver;
void *drv_priv;
struct hostapd_driver_ops drv;
void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
struct sta_info *sta, int reassoc);
void *msg_ctx; /* ctx for wpa_msg() calls */
void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
struct radius_client_data *radius;
u32 acct_session_id_hi, acct_session_id_lo;
struct radius_das_data *radius_das;
struct iapp_data *iapp;
@ -155,6 +124,10 @@ struct hostapd_data {
int parameter_set_count;
/* Time Advertisement */
u8 time_update_counter;
struct wpabuf *time_adv;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan *full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@ -162,10 +135,12 @@ struct hostapd_data {
struct l2_packet_data *l2;
struct wps_context *wps;
int beacon_set_done;
struct wpabuf *wps_beacon_ie;
struct wpabuf *wps_probe_resp_ie;
#ifdef CONFIG_WPS
unsigned int ap_pin_failures;
unsigned int ap_pin_failures_consecutive;
struct upnp_wps_device_sm *wps_upnp;
unsigned int ap_pin_lockout_time;
#endif /* CONFIG_WPS */
@ -177,9 +152,46 @@ struct hostapd_data {
int freq);
void *public_action_cb_ctx;
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *vendor_action_cb_ctx;
void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
const u8 *uuid_e);
void *wps_reg_success_cb_ctx;
void (*wps_event_cb)(void *ctx, enum wps_event event,
union wps_event_data *data);
void *wps_event_cb_ctx;
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
int authorized, const u8 *p2p_dev_addr);
void *sta_authorized_cb_ctx;
void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_ctx;
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
struct wpabuf *p2p_beacon_ie;
struct wpabuf *p2p_probe_resp_ie;
/* Number of non-P2P association stations */
int num_sta_no_p2p;
/* Periodic NoA (used only when no non-P2P clients in the group) */
int noa_enabled;
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
#endif /* CONFIG_SQLITE */
};
@ -189,8 +201,6 @@ struct hostapd_data {
struct hostapd_iface {
struct hapd_interfaces *interfaces;
void *owner;
int (*reload_config)(struct hostapd_iface *iface);
struct hostapd_config * (*config_read_cb)(const char *config_fname);
char *config_fname;
struct hostapd_config *conf;
@ -202,6 +212,14 @@ struct hostapd_iface {
struct ap_info *ap_hash[STA_HASH_SIZE];
struct ap_info *ap_iter_list;
unsigned int drv_flags;
/*
* A bitmap of supported protocols for probe response offload. See
* struct wpa_driver_capa in driver.h
*/
unsigned int probe_resp_offloads;
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
@ -209,6 +227,7 @@ struct hostapd_iface {
* current_mode->channels */
int num_rates;
struct hostapd_rate_data *current_rates;
int *basic_rates;
int freq;
u16 hw_flags;
@ -239,16 +258,12 @@ struct hostapd_iface {
u16 ht_op_mode;
void (*scan_cb)(struct hostapd_iface *iface);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
int (*for_each_interface)(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
};
/* hostapd.c */
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
int hostapd_reload_config(struct hostapd_iface *iface);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
@ -260,17 +275,35 @@ void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *ie, size_t ie_len),
const u8 *da, const u8 *bssid,
const u8 *ie, size_t ie_len,
int ssi_signal),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
/* drv_callbacks.c (TODO: move to somewhere else?) */
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen);
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
size_t identity_len, int phase2);
#endif /* HOSTAPD_H */

31
contrib/wpa/src/ap/hs20.c Normal file
View File

@ -0,0 +1,31 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2009, Atheros Communications, Inc.
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
#include "hs20.h"
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
{
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 5;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
/* Hotspot Configuration: DGAF Enabled */
*eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
return eid;
}

16
contrib/wpa/src/ap/hs20.h Normal file
View File

@ -0,0 +1,16 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef HS20_H
#define HS20_H
struct hostapd_data;
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
#endif /* HS20_H */

View File

@ -2,7 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -101,8 +101,8 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
}
static int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode)
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 };
@ -110,8 +110,8 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
int *basic_rates;
if (hapd->iconf->basic_rates)
basic_rates = hapd->iconf->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;
@ -122,22 +122,28 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
case HOSTAPD_MODE_IEEE80211G:
basic_rates = basic_rates_g;
break;
case HOSTAPD_MODE_IEEE80211AD:
return 0; /* No basic rates for 11ad */
default:
return -1;
}
if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
basic_rates, mode->mode)) {
wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
"module");
}
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(hapd->iface->current_rates);
hapd->iface->num_rates = 0;
os_free(iface->current_rates);
iface->num_rates = 0;
hapd->iface->current_rates =
os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
if (!hapd->iface->current_rates) {
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;
@ -146,26 +152,27 @@ static int hostapd_prepare_rates(struct hostapd_data *hapd,
for (i = 0; i < mode->num_rates; i++) {
struct hostapd_rate_data *rate;
if (hapd->iconf->supported_rates &&
!hostapd_rate_found(hapd->iconf->supported_rates,
if (iface->conf->supported_rates &&
!hostapd_rate_found(iface->conf->supported_rates,
mode->rates[i]))
continue;
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
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",
hapd->iface->num_rates, rate->rate, rate->flags);
hapd->iface->num_rates++;
iface->num_rates, rate->rate, rate->flags);
iface->num_rates++;
}
if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
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).",
hapd->iface->num_rates, num_basic_rates);
iface->num_rates, num_basic_rates);
return -1;
}
@ -265,11 +272,11 @@ static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
*pri_chan = oper->control_chan;
if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
if (oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
int sec = oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
*sec_chan = *pri_chan + 4;
else if (oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
*sec_chan = *pri_chan - 4;
}
}
@ -406,27 +413,14 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
}
static void wpa_scan_results_free(struct wpa_scan_results *res)
{
size_t i;
if (res == NULL)
return;
for (i = 0; i < res->num; i++)
os_free(res->res[i]);
os_free(res->res);
os_free(res);
}
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 802.11n/D7.0, 11.14.3.2 */
* allowed per IEEE Std 802.11-2012, 10.15.3.2 */
iface->scan_cb = NULL;
@ -452,7 +446,48 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
}
hostapd_setup_interface_complete(iface, 0);
res = ieee80211n_allowed_ht40_channel_pair(iface);
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;
affected_start = (pri_freq + sec_freq) / 2 - 25;
affected_end = (pri_freq + sec_freq) / 2 + 25;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
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;
}
}
@ -466,12 +501,15 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(&params, 0, sizeof(params));
/* TODO: scan only the needed frequency */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
ieee80211n_scan_channels_2g4(iface, &params);
if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
os_free(params.freqs);
return -1;
}
os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
@ -483,9 +521,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
u16 hw = iface->current_mode->ht_capab;
u16 conf = iface->conf->ht_capab;
if (!iface->conf->ieee80211n)
return 1;
if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
!(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@ -585,13 +620,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211N
int ret;
if (!iface->conf->ieee80211n)
return 0;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
ret = ieee80211n_check_40mhz(iface);
if (ret)
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211N */
return 0;
@ -601,7 +638,7 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
* Returns: 0 on success, < 0 on failure
*
* Sets up the hardware mode, channel, rates, and passive scanning
* based on the configuration.
@ -628,18 +665,58 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured mode "
"(%d)", (int) iface->conf->hw_mode);
return -1;
"(%d) (hw_mode in hostapd.conf)",
(int) iface->conf->hw_mode);
return -2;
}
ok = 0;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->chan == iface->conf->channel)) {
ok = 1;
break;
if (chan->chan == iface->conf->channel) {
if (chan->flag & HOSTAPD_CHAN_DISABLED) {
wpa_printf(MSG_ERROR,
"channel [%i] (%i) is disabled for "
"use in AP mode, flags: 0x%x%s%s%s",
j, chan->chan, chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IBSS ?
" NO-IBSS" : "",
chan->flag &
HOSTAPD_CHAN_PASSIVE_SCAN ?
" PASSIVE-SCAN" : "",
chan->flag & HOSTAPD_CHAN_RADAR ?
" RADAR" : "");
} else {
ok = 1;
break;
}
}
}
if (ok && iface->conf->secondary_channel) {
int sec_ok = 0;
int sec_chan = iface->conf->channel +
iface->conf->secondary_channel * 4;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->chan == sec_chan)) {
sec_ok = 1;
break;
}
}
if (!sec_ok) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured HT40 secondary channel "
"(%d) not found from the channel list "
"of current mode (%d) %s",
sec_chan, iface->current_mode->mode,
hostapd_hw_mode_txt(
iface->current_mode->mode));
ok = 0;
}
}
if (iface->conf->channel == 0) {
@ -647,7 +724,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
* the channel automatically */
wpa_printf(MSG_ERROR, "Channel not configured "
"(hw_mode/channel in hostapd.conf)");
return -1;
return -3;
}
if (ok == 0 && iface->conf->channel != 0) {
hostapd_logger(iface->bss[0], NULL,
@ -665,15 +742,7 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
return -1;
}
if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
return -1;
return -4;
}
return 0;
@ -689,6 +758,8 @@ const char * hostapd_hw_mode_txt(int mode)
return "IEEE 802.11b";
case HOSTAPD_MODE_IEEE80211G:
return "IEEE 802.11g";
case HOSTAPD_MODE_IEEE80211AD:
return "IEEE 802.11ad";
default:
return "UNKNOWN";
}

View File

@ -2,6 +2,7 @@
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -25,6 +26,8 @@ const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@ -39,7 +42,7 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
return -1;
return -100;
}
static inline const char * hostapd_hw_mode_txt(int mode)
@ -57,6 +60,12 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
return 0;
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */

View File

@ -2,14 +2,8 @@
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*
* Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
* and IEEE has withdrawn it. In other words, it is likely better to look at

View File

@ -2,14 +2,8 @@
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IAPP_H

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,8 @@
* hostapd / IEEE 802.11 Management
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IEEE802_11_H
@ -46,22 +40,42 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
size_t ht_capab_len);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t len, int ack);
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds);
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid);
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
const u8 *sa, const u8 action_type,
const u8 *trans_id);
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
#endif /* IEEE802_11_H */

View File

@ -1,15 +1,9 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*
* Access control list for IEEE 802.11 authentication can uses statically
* configured ACL from configuration files or an external RADIUS server.
@ -21,29 +15,35 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/sha1.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#define RADIUS_ACL_TIMEOUT 30
struct hostapd_cached_radius_acl {
time_t timestamp;
os_time_t timestamp;
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
};
struct hostapd_acl_query_data {
time_t timestamp;
os_time_t timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@ -53,6 +53,15 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
os_free(e->identity);
os_free(e->radius_cui);
hostapd_free_psk_list(e->psk);
os_free(e);
}
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
{
struct hostapd_cached_radius_acl *prev;
@ -60,38 +69,73 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
while (acl_cache) {
prev = acl_cache;
acl_cache = acl_cache->next;
os_free(prev);
hostapd_acl_cache_free_entry(prev);
}
}
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src)
{
struct hostapd_sta_wpa_psk_short **copy_to;
struct hostapd_sta_wpa_psk_short *copy_from;
/* Copy PSK linked list */
copy_to = psk;
copy_from = src;
while (copy_from && copy_to) {
*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
if (*copy_to == NULL)
break;
os_memcpy(*copy_to, copy_from,
sizeof(struct hostapd_sta_wpa_psk_short));
copy_from = copy_from->next;
copy_to = &((*copy_to)->next);
}
if (copy_to)
*copy_to = NULL;
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id)
u32 *acct_interim_interval, int *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
time_t now;
struct os_time now;
time(&now);
entry = hapd->acl_cache;
os_get_time(&now);
while (entry) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
*session_timeout =
entry->session_timeout;
if (acct_interim_interval)
*acct_interim_interval =
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
return entry->accepted;
for (entry = hapd->acl_cache; entry; entry = entry->next) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
continue;
if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
*session_timeout = entry->session_timeout;
if (acct_interim_interval)
*acct_interim_interval =
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
copy_psk_list(psk, entry->psk);
if (identity) {
if (entry->identity)
*identity = os_strdup(entry->identity);
else
*identity = NULL;
}
entry = entry->next;
if (radius_cui) {
if (entry->radius_cui)
*radius_cui = os_strdup(entry->radius_cui);
else
*radius_cui = NULL;
}
return entry->accepted;
}
return -1;
@ -137,37 +181,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
if (hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
NULL, msg) < 0)
goto fail;
}
#ifdef CONFIG_IPV6
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
goto fail;
}
#endif /* CONFIG_IPV6 */
if (hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(addr));
@ -177,12 +193,6 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
goto fail;
}
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
@ -190,7 +200,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
goto fail;
}
radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
goto fail;
return 0;
fail:
@ -209,11 +220,19 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
* @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
* The caller is responsible for freeing the returned *identity and *radius_cui
* values with os_free().
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id)
u32 *acct_interim_interval, int *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
{
if (session_timeout)
*session_timeout = 0;
@ -221,6 +240,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
if (psk)
*psk = NULL;
if (identity)
*identity = NULL;
if (radius_cui)
*radius_cui = NULL;
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@ -240,11 +265,13 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
struct os_time t;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
vlan_id);
vlan_id, psk,
identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@ -256,6 +283,14 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
if (identity) {
os_free(*identity);
*identity = NULL;
}
if (radius_cui) {
os_free(*radius_cui);
*radius_cui = NULL;
}
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@ -270,7 +305,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
time(&query->timestamp);
os_get_time(&t);
query->timestamp = t.sec;
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@ -302,7 +338,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
@ -317,12 +353,10 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
prev->next = entry->next;
else
hapd->acl_cache = entry->next;
#ifdef CONFIG_DRIVER_RADIUS_ACL
hapd->drv.set_radius_acl_expire(hapd, entry->addr);
#endif /* CONFIG_DRIVER_RADIUS_ACL */
hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
tmp = entry;
entry = entry->next;
os_free(tmp);
hostapd_acl_cache_free_entry(tmp);
continue;
}
@ -332,7 +366,8 @@ static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
}
static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
os_time_t now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
@ -368,16 +403,64 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
time_t now;
struct os_time now;
time(&now);
hostapd_acl_expire_cache(hapd, now);
hostapd_acl_expire_queries(hapd, now);
os_get_time(&now);
hostapd_acl_expire_cache(hapd, now.sec);
hostapd_acl_expire_queries(hapd, now.sec);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
static void decode_tunnel_passwords(struct hostapd_data *hapd,
const u8 *shared_secret,
size_t shared_secret_len,
struct radius_msg *msg,
struct radius_msg *req,
struct hostapd_cached_radius_acl *cache)
{
int passphraselen;
char *passphrase, *strpassphrase;
size_t i;
struct hostapd_sta_wpa_psk_short *psk;
/*
* Decode all tunnel passwords as PSK and save them into a linked list.
*/
for (i = 0; ; i++) {
passphrase = radius_msg_get_tunnel_password(
msg, &passphraselen, shared_secret, shared_secret_len,
req, i);
/*
* Passphrase is NULL iff there is no i-th Tunnel-Password
* attribute in msg.
*/
if (passphrase == NULL)
break;
/*
* passphrase does not contain the NULL termination.
* Add it here as pbkdf2_sha1() requires it.
*/
strpassphrase = os_zalloc(passphraselen + 1);
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
if (strpassphrase && psk) {
os_memcpy(strpassphrase, passphrase, passphraselen);
pbkdf2_sha1(strpassphrase,
hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len, 4096,
psk->psk, PMK_LEN);
psk->next = cache->psk;
cache->psk = psk;
psk = NULL;
}
os_free(strpassphrase);
os_free(psk);
os_free(passphrase);
}
}
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message
@ -397,6 +480,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
struct os_time t;
query = hapd->acl_queries;
prev = NULL;
@ -431,9 +515,13 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
time(&cache->timestamp);
os_get_time(&t);
cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@ -452,14 +540,35 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
cache->vlan_id = radius_msg_get_vlanid(msg);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
cache->identity = os_zalloc(len + 1);
if (cache->identity)
os_memcpy(cache->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
cache->radius_cui = os_zalloc(len + 1);
if (cache->radius_cui)
os_memcpy(cache->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
#ifdef CONFIG_DRIVER_RADIUS_ACL
hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted,
cache->session_timeout);
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
cache->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@ -522,3 +631,13 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
hostapd_acl_query_free(prev);
}
}
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
os_free(prev);
}
}

View File

@ -2,14 +2,8 @@
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IEEE802_11_AUTH_H
@ -24,8 +18,11 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id);
u32 *acct_interim_interval, int *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
#endif /* IEEE802_11_AUTH_H */

View File

@ -30,7 +30,8 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_ht_capabilities *cap;
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode)
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
hapd->conf->disable_11n)
return eid;
*pos++ = WLAN_EID_HT_CAP;
@ -58,7 +59,7 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
if (!hapd->iconf->ieee80211n)
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@ -92,7 +93,6 @@ Set to 1 (HT non-member protection) if there may be non-HT STAs
Set to 2 if only HT STAs are associated in BSS,
however and at least one 20 MHz HT STA is associated
Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
(currently non-GF HT station is considered as non-HT STA also)
*/
int hostapd_ht_operation_update(struct hostapd_iface *iface)
{
@ -130,13 +130,8 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
op_mode_changes++;
}
/* Note: currently we switch to the MIXED op mode if HT non-greenfield
* station is associated. Probably it's a theoretical case, since
* it looks like all known HT STAs support greenfield.
*/
new_op_mode = 0;
if (iface->num_sta_no_ht ||
(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
if (iface->num_sta_no_ht)
new_op_mode = OP_MODE_MIXED;
else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
&& iface->num_sta_ht_20mhz)
@ -160,11 +155,13 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
}
u16 copy_sta_ht_capab(struct sta_info *sta, const u8 *ht_capab,
size_t ht_capab_len)
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
/* Disable HT caps for STAs associated to no-HT BSSes. */
if (!ht_capab ||
ht_capab_len < sizeof(struct ieee80211_ht_capabilities)) {
ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
@ -253,8 +250,14 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
return;
os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
cap &= hapd->iconf->ht_capab;
cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
/*
* Mask out HT features we don't support, but don't overwrite
* non-symmetric features like STBC and SMPS. Just because
* we're not in dynamic SMPS mode the STA might still be.
*/
cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
/*
* STBC needs to be handled specially

View File

@ -0,0 +1,458 @@
/*
* hostapd / IEEE 802.11 Management
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_11.h"
#ifdef CONFIG_IEEE80211W
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
u8 *pos = eid;
u32 timeout, tu;
struct os_time now, passed;
*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
*pos++ = 5;
*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout > tu)
timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
else
timeout = 0;
if (timeout < hapd->conf->assoc_sa_query_max_timeout)
timeout++; /* add some extra time for local timers */
WPA_PUT_LE32(pos, timeout);
pos += 4;
return pos;
}
/* MLME-SAQuery.request */
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id)
{
struct ieee80211_mgmt mgmt;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
MACSTR, MAC2STR(addr));
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
os_memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt.da, addr, ETH_ALEN);
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
perror("ieee802_11_send_sa_query_req: send");
}
static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
const u8 *sa, const u8 *trans_id)
{
struct sta_info *sta;
struct ieee80211_mgmt resp;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
sta = ap_get_sta(hapd, sa);
if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
"from unassociated STA " MACSTR, MAC2STR(sa));
return;
}
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
MACSTR, MAC2STR(sa));
os_memset(&resp, 0, sizeof(resp));
resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(resp.da, sa, ETH_ALEN);
os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
resp.u.action.category = WLAN_ACTION_SA_QUERY;
resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
perror("ieee80211_mgmt_sa_query_request: send");
}
void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
const u8 action_type, const u8 *trans_id)
{
struct sta_info *sta;
int i;
if (action_type == WLAN_SA_QUERY_REQUEST) {
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return;
}
if (action_type != WLAN_SA_QUERY_RESPONSE) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
"Action %d", action_type);
return;
}
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
MACSTR, MAC2STR(sa));
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
/* MLME-SAQuery.confirm */
sta = ap_get_sta(hapd, sa);
if (sta == NULL || sta->sa_query_trans_id == NULL) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
"pending SA Query request found");
return;
}
for (i = 0; i < sta->sa_query_count; i++) {
if (os_memcmp(sta->sa_query_trans_id +
i * WLAN_SA_QUERY_TR_ID_LEN,
trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
break;
}
if (i >= sta->sa_query_count) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
"transaction identifier found");
return;
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Reply to pending SA Query received");
ap_sta_stop_sa_query(hapd, sta);
}
#endif /* CONFIG_IEEE80211W */
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
u8 len = 0;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
if (len < 4 && hapd->conf->interworking)
len = 4;
if (len < 3 && hapd->conf->wnm_sleep_mode)
len = 3;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
#ifdef CONFIG_WNM
if (len < 4)
len = 4;
#endif /* CONFIG_WNM */
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
*pos++ = 0x00;
*pos++ = 0x00;
*pos = 0x00;
if (hapd->conf->wnm_sleep_mode)
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
if (hapd->conf->bss_transition)
*pos |= 0x08; /* Bit 19 - BSS Transition */
pos++;
if (len < 4)
return pos;
*pos = 0x00;
#ifdef CONFIG_WNM
*pos |= 0x02; /* Bit 25 - SSID List */
#endif /* CONFIG_WNM */
if (hapd->conf->time_advertisement == 2)
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
if (hapd->conf->interworking)
*pos |= 0x80; /* Bit 31 - Interworking */
pos++;
if (len < 5)
return pos;
*pos = 0x00;
if (hapd->conf->tdls & TDLS_PROHIBIT)
*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
pos++;
if (len < 6)
return pos;
*pos = 0x00;
pos++;
if (len < 7)
return pos;
*pos = 0x00;
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
pos++;
return pos;
}
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
#ifdef CONFIG_INTERWORKING
u8 *len;
if (!hapd->conf->interworking)
return eid;
*pos++ = WLAN_EID_INTERWORKING;
len = pos++;
*pos = hapd->conf->access_network_type;
if (hapd->conf->internet)
*pos |= INTERWORKING_ANO_INTERNET;
if (hapd->conf->asra)
*pos |= INTERWORKING_ANO_ASRA;
if (hapd->conf->esr)
*pos |= INTERWORKING_ANO_ESR;
if (hapd->conf->uesa)
*pos |= INTERWORKING_ANO_UESA;
pos++;
if (hapd->conf->venue_info_set) {
*pos++ = hapd->conf->venue_group;
*pos++ = hapd->conf->venue_type;
}
if (!is_zero_ether_addr(hapd->conf->hessid)) {
os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
pos += ETH_ALEN;
}
*len = pos - len - 1;
#endif /* CONFIG_INTERWORKING */
return pos;
}
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
#ifdef CONFIG_INTERWORKING
/* TODO: Separate configuration for ANQP? */
if (!hapd->conf->interworking)
return eid;
*pos++ = WLAN_EID_ADV_PROTO;
*pos++ = 2;
*pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
*pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
#endif /* CONFIG_INTERWORKING */
return pos;
}
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
#ifdef CONFIG_INTERWORKING
u8 *len;
unsigned int i, count;
if (!hapd->conf->interworking ||
hapd->conf->roaming_consortium == NULL ||
hapd->conf->roaming_consortium_count == 0)
return eid;
*pos++ = WLAN_EID_ROAMING_CONSORTIUM;
len = pos++;
/* Number of ANQP OIs (in addition to the max 3 listed here) */
if (hapd->conf->roaming_consortium_count > 3 + 255)
*pos++ = 255;
else if (hapd->conf->roaming_consortium_count > 3)
*pos++ = hapd->conf->roaming_consortium_count - 3;
else
*pos++ = 0;
/* OU #1 and #2 Lengths */
*pos = hapd->conf->roaming_consortium[0].len;
if (hapd->conf->roaming_consortium_count > 1)
*pos |= hapd->conf->roaming_consortium[1].len << 4;
pos++;
if (hapd->conf->roaming_consortium_count > 3)
count = 3;
else
count = hapd->conf->roaming_consortium_count;
for (i = 0; i < count; i++) {
os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
hapd->conf->roaming_consortium[i].len);
pos += hapd->conf->roaming_consortium[i].len;
}
*len = pos - len - 1;
#endif /* CONFIG_INTERWORKING */
return pos;
}
u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
{
if (hapd->conf->time_advertisement != 2)
return eid;
if (hapd->time_adv == NULL &&
hostapd_update_time_adv(hapd) < 0)
return eid;
if (hapd->time_adv == NULL)
return eid;
os_memcpy(eid, wpabuf_head(hapd->time_adv),
wpabuf_len(hapd->time_adv));
eid += wpabuf_len(hapd->time_adv);
return eid;
}
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
{
size_t len;
if (hapd->conf->time_advertisement != 2)
return eid;
len = os_strlen(hapd->conf->time_zone);
*eid++ = WLAN_EID_TIME_ZONE;
*eid++ = len;
os_memcpy(eid, hapd->conf->time_zone, len);
eid += len;
return eid;
}
int hostapd_update_time_adv(struct hostapd_data *hapd)
{
const int elen = 2 + 1 + 10 + 5 + 1;
struct os_time t;
struct os_tm tm;
u8 *pos;
if (hapd->conf->time_advertisement != 2)
return 0;
if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
return -1;
if (!hapd->time_adv) {
hapd->time_adv = wpabuf_alloc(elen);
if (hapd->time_adv == NULL)
return -1;
pos = wpabuf_put(hapd->time_adv, elen);
} else
pos = wpabuf_mhead_u8(hapd->time_adv);
*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
*pos++ = 1 + 10 + 5 + 1;
*pos++ = 2; /* UTC time at which the TSF timer is 0 */
/* Time Value at TSF 0 */
/* FIX: need to calculate this based on the current TSF value */
WPA_PUT_LE16(pos, tm.year); /* Year */
pos += 2;
*pos++ = tm.month; /* Month */
*pos++ = tm.day; /* Day of month */
*pos++ = tm.hour; /* Hours */
*pos++ = tm.min; /* Minutes */
*pos++ = tm.sec; /* Seconds */
WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
pos += 2;
*pos++ = 0; /* Reserved */
/* Time Error */
/* TODO: fill in an estimate on the error */
*pos++ = 0;
*pos++ = 0;
*pos++ = 0;
*pos++ = 0;
*pos++ = 0;
*pos++ = hapd->time_update_counter++;
return 0;
}
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
#ifdef CONFIG_WNM
if (hapd->conf->ap_max_inactivity > 0) {
unsigned int val;
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
*pos++ = 3;
val = hapd->conf->ap_max_inactivity;
if (val > 68000)
val = 68000;
val *= 1000;
val /= 1024;
if (val == 0)
val = 1;
if (val > 65535)
val = 65535;
WPA_PUT_LE16(pos, val);
pos += 2;
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
}
#endif /* CONFIG_WNM */
return pos;
}

View File

@ -0,0 +1,110 @@
/*
* hostapd / IEEE 802.11ac VHT
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of BSD license
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_capabilities *cap;
u8 *pos = eid;
if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
hapd->conf->disable_11ac)
return eid;
*pos++ = WLAN_EID_VHT_CAP;
*pos++ = sizeof(*cap);
cap = (struct ieee80211_vht_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
cap->vht_capabilities_info = host_to_le32(
hapd->iface->current_mode->vht_capab);
/* Supported MCS set comes from hw */
os_memcpy(cap->vht_supported_mcs_set,
hapd->iface->current_mode->vht_mcs_set, 8);
pos += sizeof(*cap);
return pos;
}
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
return eid;
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
oper = (struct ieee80211_vht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
/*
* center freq = 5 GHz + (5 * index)
* So index 42 gives center freq 5.210 GHz
* which is channel 42 in 5G band
*/
oper->vht_op_info_chan_center_freq_seg0_idx =
hapd->iconf->vht_oper_centr_freq_seg0_idx;
oper->vht_op_info_chan_center_freq_seg1_idx =
hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
/* VHT Basic MCS set comes from hw */
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
oper->vht_basic_mcs_set = host_to_le16(0xfffc);
pos += sizeof(*oper);
return pos;
}
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
hapd->conf->disable_11ac) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
sta->vht_capabilities = NULL;
return WLAN_STATUS_SUCCESS;
}
if (sta->vht_capabilities == NULL) {
sta->vht_capabilities =
os_zalloc(sizeof(struct ieee80211_vht_capabilities));
if (sta->vht_capabilities == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
sta->flags |= WLAN_STA_VHT;
os_memcpy(sta->vht_capabilities, vht_capab,
sizeof(struct ieee80211_vht_capabilities));
return WLAN_STATUS_SUCCESS;
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -18,14 +12,15 @@
#include "utils/eloop.h"
#include "crypto/md5.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "eap_server/eap.h"
#include "eap_common/eap_wsc_common.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
#include "sta_info.h"
@ -33,6 +28,7 @@
#include "preauth_auth.h"
#include "pmksa_cache_auth.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_1x.h"
@ -70,7 +66,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt);
hostapd_drv_hapd_send_eapol(
hapd, sta->addr, buf, len,
encrypt, hostapd_sta_flags_to_drv(sta->flags));
}
os_free(buf);
@ -86,21 +84,13 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
return;
if (authorized) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
wpa_msg(hapd->msg_ctx, MSG_INFO,
AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
sta->flags |= WLAN_STA_AUTHORIZED;
res = hapd->drv.set_authorized(hapd, sta, 1);
ap_sta_set_authorized(hapd, sta, 1);
res = hostapd_set_authorized(hapd, sta, 1);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "authorizing port");
} else {
if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) ==
(WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC))
wpa_msg(hapd->msg_ctx, MSG_INFO,
AP_STA_DISCONNECTED MACSTR,
MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_AUTHORIZED;
res = hapd->drv.set_authorized(hapd, sta, 0);
ap_sta_set_authorized(hapd, sta, 0);
res = hostapd_set_authorized(hapd, sta, 0);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
}
@ -110,8 +100,10 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
"driver (errno=%d).\n", MAC2STR(sta->addr), errno);
}
if (authorized)
if (authorized) {
os_get_time(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
}
@ -137,10 +129,10 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
hdr = (struct ieee802_1x_hdr *) buf;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
key->type = EAPOL_KEY_TYPE_RC4;
key->key_length = htons(key_len);
WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
if (os_get_random(key->key_iv, sizeof(key->key_iv))) {
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
wpa_printf(MSG_ERROR, "Could not get random numbers");
os_free(buf);
return;
@ -215,7 +207,7 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
if (!key->key[key->idx])
key->key[key->idx] = os_malloc(key->default_len);
if (key->key[key->idx] == NULL ||
os_get_random(key->key[key->idx], key->default_len)) {
random_get_bytes(key->key[key->idx], key->default_len)) {
printf("Could not generate random WEP key (dynamic VLAN).\n");
os_free(key->key[key->idx]);
key->key[key->idx] = NULL;
@ -229,11 +221,13 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
key->key[key->idx], key->len[key->idx]);
if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1,
NULL, 0, key->key[key->idx], key->len[key->idx]))
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
broadcast_ether_addr, key->idx, 1,
NULL, 0, key->key[key->idx],
key->len[key->idx]))
printf("Could not set dynamic VLAN WEP encryption key.\n");
hapd->drv.set_drv_ieee8021x(hapd, ifname, 1);
hostapd_set_drv_ieee8021x(hapd, ifname, 1);
return key;
}
@ -330,7 +324,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
u8 *ikey;
ikey = os_malloc(hapd->conf->individual_wep_key_len);
if (ikey == NULL ||
os_get_random(ikey, hapd->conf->individual_wep_key_len)) {
random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
{
wpa_printf(MSG_ERROR, "Could not generate random "
"individual WEP key.");
os_free(ikey);
@ -345,9 +340,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
sta->addr, 0, 1, NULL, 0, ikey,
hapd->conf->individual_wep_key_len)) {
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
sta->addr, 0, 1, NULL, 0, ikey,
hapd->conf->individual_wep_key_len)) {
wpa_printf(MSG_ERROR, "Could not set individual WEP "
"encryption.");
}
@ -360,6 +355,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
const char *radius_mode_txt(struct hostapd_data *hapd)
{
switch (hapd->iface->conf->hw_mode) {
case HOSTAPD_MODE_IEEE80211AD:
return "802.11ad";
case HOSTAPD_MODE_IEEE80211A:
return "802.11a";
case HOSTAPD_MODE_IEEE80211G:
@ -417,12 +414,142 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
}
static int add_common_radius_sta_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg)
{
char buf[128];
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_PORT) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
wpa_printf(MSG_ERROR, "Could not add NAS-Port");
return -1;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(sta->addr));
buf[sizeof(buf) - 1] = '\0';
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
return -1;
}
if (sta->flags & WLAN_STA_PREAUTH) {
os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
sizeof(buf));
} else {
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
buf[sizeof(buf) - 1] = '\0';
}
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CONNECT_INFO) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_ERROR, "Could not add Connect-Info");
return -1;
}
if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
os_snprintf(buf, sizeof(buf), "%08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
return -1;
}
}
return 0;
}
int add_common_radius_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg)
{
char buf[128];
struct hostapd_radius_attr *attr;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
return -1;
}
#ifdef CONFIG_IPV6
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
return -1;
}
#endif /* CONFIG_IPV6 */
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IDENTIFIER) &&
hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
return -1;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr),
wpa_ssid_txt(hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len));
buf[sizeof(buf) - 1] = '\0';
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CALLED_STATION_ID) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
return -1;
}
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_PORT_TYPE) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
return -1;
}
if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
return -1;
for (attr = req_attr; attr; attr = attr->next) {
if (!radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val))) {
wpa_printf(MSG_ERROR, "Could not add RADIUS "
"attribute");
return -1;
}
}
return 0;
}
static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
{
struct radius_msg *msg;
char buf[128];
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
@ -450,83 +577,20 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
if (hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
msg) < 0)
goto fail;
}
#ifdef CONFIG_IPV6
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
goto fail;
}
#endif /* CONFIG_IPV6 */
if (hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
printf("Could not add NAS-Identifier\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
buf[sizeof(buf) - 1] = '\0';
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(sta->addr));
buf[sizeof(buf) - 1] = '\0';
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
goto fail;
}
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
RADIUS_ATTR_FRAMED_MTU) &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
printf("Could not add Framed-MTU\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
}
if (sta->flags & WLAN_STA_PREAUTH) {
os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
sizeof(buf));
} else {
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
buf[sizeof(buf) - 1] = '\0';
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
}
if (eap && !radius_msg_add_eap(msg, eap, len)) {
printf("Could not add EAP-Message\n");
goto fail;
@ -549,7 +613,28 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
}
}
radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr);
if (hapd->conf->radius_request_cui) {
const u8 *cui;
size_t cui_len;
/* Add previously learned CUI or nul CUI to request CUI */
if (sm->radius_cui) {
cui = wpabuf_head(sm->radius_cui);
cui_len = wpabuf_len(sm->radius_cui);
} else {
cui = (const u8 *) "\0";
cui_len = 1;
}
if (!radius_msg_add_attr(msg,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
cui, cui_len)) {
wpa_printf(MSG_ERROR, "Could not add CUI");
goto fail;
}
}
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
return;
fail:
@ -652,7 +737,8 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
flags |= EAPOL_SM_FROM_PMKSA_CACHE;
}
return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
sta->wps_ie, sta);
sta->wps_ie, sta->p2p_ie, sta,
sta->identity, sta->radius_cui);
}
@ -673,6 +759,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
struct ieee802_1x_eapol_key *key;
u16 datalen;
struct rsn_pmksa_cache_entry *pmksa;
int key_mgmt;
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
!hapd->conf->wps_state)
@ -681,9 +768,10 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
(unsigned long) len, MAC2STR(sa));
sta = ap_get_sta(hapd, sa);
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated STA");
"associated/Pre-authenticating STA");
return;
}
@ -724,10 +812,19 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
}
if ((!hapd->conf->ieee802_1x &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) ||
wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
if (!hapd->conf->ieee802_1x &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
"802.1X not enabled and WPS not used");
return;
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
"STA is using PSK");
return;
}
if (!sta->eapol_sm) {
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
@ -735,14 +832,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
#ifdef CONFIG_WPS
if (!hapd->conf->ieee802_1x &&
((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
WLAN_STA_MAYBE_WPS)) {
/*
* Delay EAPOL frame transmission until a possible WPS
* STA initiates the handshake with EAPOL-Start.
*/
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
if (!hapd->conf->ieee802_1x) {
u32 wflags = sta->flags & (WLAN_STA_WPS |
WLAN_STA_WPS2 |
WLAN_STA_MAYBE_WPS);
if (wflags == WLAN_STA_MAYBE_WPS ||
wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
/*
* Delay EAPOL frame transmission until a
* possible WPS STA initiates the handshake
* with EAPOL-Start. Only allow the wait to be
* skipped if the STA is known to support WPS
* 2.0.
*/
wpa_printf(MSG_DEBUG, "WPS: Do not start "
"EAPOL until EAPOL-Start is "
"received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
}
#endif /* CONFIG_WPS */
@ -776,6 +883,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
}
sta->eapol_sm->eapolStart = TRUE;
sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
break;
@ -788,11 +896,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
accounting_sta_stop(hapd, sta);
sta->eapol_sm->eapolLogoff = TRUE;
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
break;
case IEEE802_1X_TYPE_EAPOL_KEY:
wpa_printf(MSG_DEBUG, " EAPOL-Key");
if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
if (!ap_sta_is_authorized(sta)) {
wpa_printf(MSG_DEBUG, " Dropped key data from "
"unauthorized Supplicant");
break;
@ -827,6 +936,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
struct rsn_pmksa_cache_entry *pmksa;
int reassoc = 1;
int force_1x = 0;
int key_mgmt;
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->conf->wpa &&
@ -840,9 +950,27 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_WPS */
if ((!force_1x && !hapd->conf->ieee802_1x) ||
wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
if (!force_1x && !hapd->conf->ieee802_1x) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
"802.1X not enabled or forced for WPS");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPS to PSK.
*/
ieee802_1x_free_station(sta);
return;
}
key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
/*
* Clear any possible EAPOL authenticator state to support
* reassociation change from WPA-EAP to PSK.
*/
ieee802_1x_free_station(sta);
return;
}
if (sta->eapol_sm == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@ -860,17 +988,40 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_WPS
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
/*
* Delay EAPOL frame transmission until a possible WPS
* initiates the handshake with EAPOL-Start.
* Delay EAPOL frame transmission until a possible WPS STA
* initiates the handshake with EAPOL-Start. Only allow the
* wait to be skipped if the STA is known to support WPS 2.0.
*/
wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
"EAPOL-Start is received");
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
sta->eapol_sm->eap_if->portEnabled = TRUE;
#ifdef CONFIG_IEEE80211R
if (sta->auth_alg == WLAN_AUTH_FT) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"PMK from FT - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FT information from R0KH. */
sta->eapol_sm->keyRun = TRUE;
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE;
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
/* TODO: get vlan_id from R0KH using RRB message */
return;
}
#endif /* CONFIG_IEEE80211R */
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
int old_vlanid;
@ -885,6 +1036,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE;
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
old_vlanid = sta->vlan_id;
@ -918,6 +1070,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
#ifndef CONFIG_NO_RADIUS
radius_msg_free(sm->last_recv_radius);
radius_free_class(&sm->radius_class);
wpabuf_free(sm->radius_cui);
#endif /* CONFIG_NO_RADIUS */
os_free(sm->identity);
@ -929,9 +1082,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta)
{
u8 *eap;
size_t len;
struct eap_hdr *hdr;
struct wpabuf *eap;
const struct eap_hdr *hdr;
int eap_type = -1;
char buf[64];
struct radius_msg *msg;
@ -945,7 +1097,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
msg = sm->last_recv_radius;
eap = radius_msg_get_eap(msg, &len);
eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
@ -957,19 +1109,19 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
return;
}
if (len < sizeof(*hdr)) {
if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "too short EAP packet "
"received from authentication server");
os_free(eap);
wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE;
return;
}
if (len > sizeof(*hdr))
eap_type = eap[sizeof(*hdr)];
if (wpabuf_len(eap) > sizeof(*hdr))
eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
hdr = (struct eap_hdr *) eap;
hdr = wpabuf_head(eap);
switch (hdr->code) {
case EAP_CODE_REQUEST:
if (eap_type >= 0)
@ -1004,7 +1156,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
sm->eap_if->aaaEapReq = TRUE;
wpabuf_free(sm->eap_if->aaaEapReqData);
sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
sm->eap_if->aaaEapReqData = eap;
}
@ -1069,7 +1221,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
if (count <= 0)
return;
nclass = os_zalloc(count * sizeof(struct radius_attr_data));
nclass = os_calloc(count, sizeof(struct radius_attr_data));
if (nclass == NULL)
return;
@ -1139,6 +1291,32 @@ static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
}
/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
struct sta_info *sta,
struct radius_msg *msg)
{
struct eapol_state_machine *sm = sta->eapol_sm;
struct wpabuf *cui;
u8 *buf;
size_t len;
if (sm == NULL)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) < 0)
return;
cui = wpabuf_alloc_copy(buf, len);
if (cui == NULL)
return;
wpabuf_free(sm->radius_cui);
sm->radius_cui = cui;
}
struct sta_id_search {
u8 identifier;
struct eapol_state_machine *sm;
@ -1298,6 +1476,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
shared_secret_len);
ieee802_1x_store_radius_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
ieee802_1x_update_sta_cui(hapd, sta, msg);
if (sm->eap_if->eapKeyAvailable &&
wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
session_timeout_set ?
@ -1363,6 +1542,9 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
* request and we cannot continue EAP processing (EAP-Failure
* could only be sent if the EAP peer actually replied).
*/
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
MAC2STR(sta->addr));
sm->eap_if->portEnabled = FALSE;
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@ -1380,8 +1562,8 @@ static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
os_free(eapol->default_wep_key);
eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
if (eapol->default_wep_key == NULL ||
os_get_random(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
random_get_bytes(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
printf("Could not generate random WEP key.\n");
os_free(eapol->default_wep_key);
eapol->default_wep_key = NULL;
@ -1432,10 +1614,11 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
/* TODO: Could setup key for RX here, but change default TX keyid only
* after new broadcast key has been sent to all stations. */
if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL,
eapol->default_wep_key_idx, 1, NULL, 0,
eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
broadcast_ether_addr,
eapol->default_wep_key_idx, 1, NULL, 0,
eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "failed to configure a "
"new broadcast key");
@ -1514,19 +1697,15 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
{
struct hostapd_data *hapd = ctx;
const struct hostapd_eap_user *eap_user;
int i, count;
int i;
eap_user = hostapd_get_eap_user(hapd->conf, identity,
identity_len, phase2);
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
count = EAP_USER_MAX_METHODS;
if (count > EAP_MAX_METHODS)
count = EAP_MAX_METHODS;
for (i = 0; i < count; i++) {
for (i = 0; i < EAP_MAX_METHODS; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
@ -1538,6 +1717,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
@ -1651,6 +1831,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
conf.tnc = hapd->conf->tnc;
conf.wps = hapd->wps;
conf.fragment_size = hapd->conf->fragment_size;
conf.pwd_group = hapd->conf->pwd_group;
conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
@ -1669,7 +1852,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
return -1;
if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
return -1;
#ifndef CONFIG_NO_RADIUS
@ -1680,9 +1863,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
if (hapd->conf->default_wep_key_len) {
for (i = 0; i < 4; i++)
hapd->drv.set_key(hapd->conf->iface, hapd,
WPA_ALG_NONE, NULL, i, 0, NULL, 0,
NULL, 0);
hostapd_drv_set_key(hapd->conf->iface, hapd,
WPA_ALG_NONE, NULL, i, 0, NULL, 0,
NULL, 0);
ieee802_1x_rekey(hapd, NULL);
@ -1700,7 +1883,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
if (hapd->driver != NULL &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
eapol_auth_deinit(hapd->eapol_auth);
hapd->eapol_auth = NULL;
@ -1711,15 +1894,13 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack)
{
struct ieee80211_hdr *hdr;
struct ieee802_1x_hdr *xhdr;
struct ieee802_1x_eapol_key *key;
u8 *pos;
const unsigned char rfc1042_hdr[ETH_ALEN] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
if (sta == NULL)
return -1;
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
return 0;
hdr = (struct ieee80211_hdr *) buf;
@ -1731,21 +1912,44 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
pos += 2;
xhdr = (struct ieee802_1x_hdr *) pos;
pos += sizeof(*xhdr);
return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
ack);
}
int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, int len, int ack)
{
const struct ieee802_1x_hdr *xhdr =
(const struct ieee802_1x_hdr *) buf;
const u8 *pos = buf + sizeof(*xhdr);
struct ieee802_1x_eapol_key *key;
if (len < (int) sizeof(*xhdr))
return 0;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
"type=%d length=%d - ack=%d",
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
return 0;
if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
const struct wpa_eapol_key *wpa;
wpa = (const struct wpa_eapol_key *) pos;
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
wpa->type == EAPOL_KEY_TYPE_WPA)
wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
sta->wpa_sm, ack);
}
/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
* or Authenticator state machines, but EAPOL-Key packets are not
* retransmitted in case of failure. Try to re-sent failed EAPOL-Key
* retransmitted in case of failure. Try to re-send failed EAPOL-Key
* packets couple of times because otherwise STA keys become
* unsynchronized with AP. */
if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
pos + sizeof(*key) <= buf + len) {
if (!ack && pos + sizeof(*key) <= buf + len) {
key = (struct ieee802_1x_eapol_key *) pos;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
@ -1789,8 +1993,17 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
}
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
{
if (sm == NULL)
return NULL;
return sm->radius_cui;
}
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
*len = 0;
if (sm == NULL)
return NULL;
@ -1848,6 +2061,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
{
int len = 0, ret;
struct eapol_state_machine *sm = sta->eapol_sm;
struct os_time t;
if (sm == NULL)
return 0;
@ -1962,6 +2176,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
len += ret;
/* dot1xAuthSessionStatsTable */
os_get_time(&t);
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
@ -1976,8 +2191,7 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
(wpa_key_mgmt_wpa_ieee8021x(
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
(unsigned int) (time(NULL) -
sta->acct_session_start),
(unsigned int) (t.sec - sta->acct_session_start),
sm->identity);
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
@ -2004,22 +2218,25 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
"Added PMKSA cache entry (IEEE 802.1X)");
}
#ifdef CONFIG_WPS
if (!success && (sta->flags & WLAN_STA_WPS)) {
if (!success) {
/*
* Many devices require deauthentication after WPS provisioning
* and some may not be be able to do that themselves, so
* disconnect the client here.
* disconnect the client here. In addition, this may also
* benefit IEEE 802.1X/EAPOL authentication cases, too since
* the EAPOL PAE state machine would remain in HELD state for
* considerable amount of time and some EAP methods, like
* EAP-FAST with anonymous provisioning, may require another
* EAPOL authentication to be started to complete connection.
*/
wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
"EAP-Failure");
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
"disconnection after EAP-Failure");
/* Add a small sleep to increase likelihood of previously
* requested EAP-Failure TX getting out before this should the
* driver reorder operations.
*/
os_sleep(0, 10000);
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
}
#endif /* CONFIG_WPS */
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IEEE802_1X_H
@ -20,38 +14,8 @@ struct sta_info;
struct eapol_state_machine;
struct hostapd_config;
struct hostapd_bss_config;
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
/* RFC 3580, 4. RC4 EAPOL-Key Frame */
struct ieee802_1x_eapol_key {
u8 type;
u16 key_length;
u8 replay_counter[8]; /* does not repeat within the life of the keying
* material used to encrypt the Key field;
* 64-bit NTP timestamp MAY be used here */
u8 key_iv[16]; /* cryptographically random number */
u8 key_index; /* key flag in the most significant bit:
* 0 = broadcast (default key),
* 1 = unicast (key mapping key); key index is in the
* 7 least significant bits */
u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
* MS-MPPE-Send-Key as the key */
/* followed by key: if packet body length = 44 + key length, then the
* key field (of key_length bytes) contains the key in encrypted form;
* if packet body length = 44, key field is absent and key_length
* represents the number of least significant octets from
* MS-MPPE-Send-Key attribute to be used as the keying material;
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
struct hostapd_radius_attr;
struct radius_msg;
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
@ -68,9 +32,12 @@ int ieee802_1x_init(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);
int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *data, int len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
@ -86,4 +53,9 @@ char *eap_type_text(u8 type);
const char *radius_mode_txt(struct hostapd_data *hapd);
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
int add_common_radius_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
#endif /* IEEE802_1X_H */

View File

@ -0,0 +1,114 @@
/*
* hostapd / P2P integration
* Copyright (c) 2009-2010, Atheros Communications
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "sta_info.h"
#include "p2p_hostapd.h"
#ifdef CONFIG_P2P
int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen)
{
if (sta->p2p_ie == NULL)
return 0;
return p2p_ie_text(sta->p2p_ie, buf, buf + buflen);
}
int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration)
{
wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d "
"duration=%d", count, start, duration);
if (count == 0) {
hapd->noa_enabled = 0;
hapd->noa_start = 0;
hapd->noa_duration = 0;
}
if (count != 255) {
wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set "
"NoA parameters");
return hostapd_driver_set_noa(hapd, count, start, duration);
}
hapd->noa_enabled = 1;
hapd->noa_start = start;
hapd->noa_duration = duration;
if (hapd->num_sta_no_p2p == 0) {
wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update "
"periodic NoA parameters");
return hostapd_driver_set_noa(hapd, count, start, duration);
}
wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable "
"periodic NoA");
return 0;
}
void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected");
if (hapd->noa_enabled) {
wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA");
hostapd_driver_set_noa(hapd, 0, 0, 0);
}
}
void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected");
if (hapd->noa_enabled) {
wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA");
hostapd_driver_set_noa(hapd, 255, hapd->noa_start,
hapd->noa_duration);
}
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
{
u8 bitmap;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 4 + 3 + 1;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = P2P_OUI_TYPE;
*eid++ = P2P_ATTR_MANAGEABILITY;
WPA_PUT_LE16(eid, 1);
eid += 2;
bitmap = P2P_MAN_DEVICE_MANAGEMENT;
if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
*eid++ = bitmap;
return eid;
}
#endif /* CONFIG_P2P_MANAGER */

View File

@ -0,0 +1,35 @@
/*
* hostapd / P2P integration
* Copyright (c) 2009-2010, Atheros Communications
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef P2P_HOSTAPD_H
#define P2P_HOSTAPD_H
#ifdef CONFIG_P2P
int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration);
void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd);
void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd);
#else /* CONFIG_P2P */
static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
return 0;
}
#endif /* CONFIG_P2P */
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid);
#endif /* P2P_HOSTAPD_H */

View File

@ -2,14 +2,8 @@
* hostapd - PeerKey for Direct Link Setup (DLS)
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -18,6 +12,7 @@
#include "utils/eloop.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
#include "wpa_auth_ie.h"
@ -294,7 +289,7 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
return;
}
if (os_get_random(smk, PMK_LEN)) {
if (random_get_bytes(smk, PMK_LEN)) {
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
return;
}

View File

@ -1,15 +1,9 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -46,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
if (entry == NULL)
return;
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
@ -100,11 +95,9 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
os_get_time(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->spa));
pmksa_cache_free_entry(pmksa, entry);
MACSTR, MAC2STR(pmksa->pmksa->spa));
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
}
pmksa_cache_set_expiration(pmksa);
@ -142,6 +135,9 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
}
}
if (eapol->radius_cui)
entry->cui = wpabuf_dup(eapol->radius_cui);
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &eapol->radius_class);
#endif /* CONFIG_NO_RADIUS */
@ -169,6 +165,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
eapol->identity, eapol->identity_len);
}
if (entry->cui) {
wpabuf_free(eapol->radius_cui);
eapol->radius_cui = wpabuf_dup(entry->cui);
}
#ifndef CONFIG_NO_RADIUS
radius_free_class(&eapol->radius_class);
radius_copy_class(&eapol->radius_class, &entry->radius_class);
@ -208,6 +209,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
pmksa->pmksa_count++;
if (prev == NULL)
pmksa_cache_set_expiration(pmksa);
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
MAC2STR(entry->spa));
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
@ -305,6 +308,8 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
old_entry->identity_len);
}
}
if (old_entry->cui)
entry->cui = wpabuf_dup(old_entry->cui);
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */

View File

@ -1,15 +1,9 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef PMKSA_CACHE_H
@ -31,6 +25,7 @@ struct rsn_pmksa_cache_entry {
u8 *identity;
size_t identity_len;
struct wpabuf *cui;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
int vlan_id;

View File

@ -2,14 +2,8 @@
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"

View File

@ -2,14 +2,8 @@
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef PREAUTH_H

View File

@ -1,15 +1,9 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -17,27 +11,36 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
#include "ieee802_1x.h"
#include "ieee802_11.h"
#include "ieee802_11_auth.h"
#include "wpa_auth.h"
#include "preauth_auth.h"
#include "ap_config.h"
#include "beacon.h"
#include "ap_mlme.h"
#include "vlan_init.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "gas_serv.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@ -121,11 +124,14 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
accounting_sta_stop(hapd, sta);
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
if (sta->flags & WLAN_STA_WDS)
hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 0);
hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
if (!(sta->flags & WLAN_STA_PREAUTH))
hapd->drv.sta_remove(hapd, sta->addr);
hostapd_drv_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@ -173,6 +179,15 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
hapd->iface->num_sta_ht_20mhz--;
}
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
hapd->num_sta_no_p2p--;
if (hapd->num_sta_no_p2p == 0)
hostapd_p2p_non_p2p_sta_disconnected(hapd);
}
#endif /* CONFIG_P2P */
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
@ -181,8 +196,12 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
__func__, MAC2STR(sta->addr));
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
@ -199,9 +218,27 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
#ifdef CONFIG_INTERWORKING
if (sta->gas_dialog) {
int i;
for (i = 0; i < GAS_DIALOG_MAX; i++)
gas_serv_dialog_clear(&sta->gas_dialog[i]);
os_free(sta->gas_dialog);
}
#endif /* CONFIG_INTERWORKING */
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
wpabuf_free(sta->hs20_ie);
os_free(sta->ht_capabilities);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
os_free(sta);
}
@ -241,6 +278,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
__func__, MAC2STR(sta->addr), sta->flags,
sta->timeout_next);
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@ -253,27 +293,51 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
int inactive_sec;
wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:",
MAC2STR(sta->addr));
inactive_sec = hapd->drv.get_inact_sec(hapd, sta->addr);
/*
* Add random value to timeout so that we don't end up bouncing
* all stations at the same time if we have lots of associated
* stations that are idle (but keep re-associating).
*/
int fuzz = os_random() % 20;
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
if (inactive_sec == -1) {
wpa_printf(MSG_DEBUG, "Could not get station info "
"from kernel driver for " MACSTR ".",
MAC2STR(sta->addr));
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Check inactivity: Could not "
"get station info from kernel driver for "
MACSTR, MAC2STR(sta->addr));
/*
* The driver may not support this functionality.
* Anyway, try again after the next inactivity timeout,
* but do not disconnect the station now.
*/
next_time = hapd->conf->ap_max_inactivity + fuzz;
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
sta->flags & WLAN_STA_ASSOC) {
/* station activity detected; reset timeout state */
wpa_printf(MSG_DEBUG, " Station has been active");
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity -
next_time = hapd->conf->ap_max_inactivity + fuzz -
inactive_sec;
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been "
"inactive too long: %d sec, max allowed: %d",
MAC2STR(sta->addr), inactive_sec,
hapd->conf->ap_max_inactivity);
if (hapd->conf->skip_inactivity_poll)
sta->timeout_next = STA_DISASSOC;
}
}
if ((sta->flags & WLAN_STA_ASSOC) &&
sta->timeout_next == STA_DISASSOC &&
!(sta->flags & WLAN_STA_PENDING_POLL)) {
wpa_printf(MSG_DEBUG, " Station has ACKed data poll");
!(sta->flags & WLAN_STA_PENDING_POLL) &&
!hapd->conf->skip_inactivity_poll) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
" has ACKed data poll", MAC2STR(sta->addr));
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
@ -281,6 +345,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
}
if (next_time) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%lu seconds)",
__func__, MAC2STR(sta->addr), next_time);
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
sta);
return;
@ -288,52 +355,24 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
if (sta->timeout_next == STA_NULLFUNC &&
(sta->flags & WLAN_STA_ASSOC)) {
#ifndef CONFIG_NATIVE_WINDOWS
/* send data frame to poll STA and check whether this frame
* is ACKed */
struct ieee80211_hdr hdr;
wpa_printf(MSG_DEBUG, " Polling STA with data frame");
wpa_printf(MSG_DEBUG, " Polling STA");
sta->flags |= WLAN_STA_PENDING_POLL;
os_memset(&hdr, 0, sizeof(hdr));
if (hapd->driver &&
os_strcmp(hapd->driver->name, "hostap") == 0) {
/*
* WLAN_FC_STYPE_NULLFUNC would be more appropriate,
* but it is apparently not retried so TX Exc events
* are not received for it.
*/
hdr.frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA,
WLAN_FC_STYPE_DATA);
} else {
hdr.frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA,
WLAN_FC_STYPE_NULLFUNC);
}
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
if (hapd->drv.send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0)
perror("ap_handle_timer: send");
#endif /* CONFIG_NATIVE_WINDOWS */
hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
sta->flags & WLAN_STA_WMM);
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
MAC2STR(sta->addr));
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"Timeout, sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
MAC2STR(sta->addr));
if (deauth) {
hapd->drv.sta_deauth(hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_drv_sta_deauth(
hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
} else {
hapd->drv.sta_disassoc(
hostapd_drv_sta_disassoc(
hapd, sta->addr,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
}
@ -342,10 +381,14 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
switch (sta->timeout_next) {
case STA_NULLFUNC:
sta->timeout_next = STA_DISASSOC;
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
__func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
hapd, sta);
break;
case STA_DISASSOC:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
@ -357,6 +400,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
__func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
@ -366,7 +412,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
case STA_REMOVE:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"inactivity");
"inactivity (timer DEAUTH/REMOVE)");
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@ -385,8 +431,14 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH))
if (!(sta->flags & WLAN_STA_AUTH)) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
}
return;
}
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@ -397,7 +449,7 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
}
@ -441,8 +493,13 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
accounting_sta_get_id(hapd, sta);
/* initialize STA info data */
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
__func__, MAC2STR(addr),
hapd->conf->ap_max_inactivity);
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
@ -463,7 +520,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
MAC2STR(sta->addr));
if (hapd->drv.sta_remove(hapd, sta->addr) &&
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
sta->flags & WLAN_STA_ASSOC) {
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
" from kernel driver.", MAC2STR(sta->addr));
@ -498,21 +555,51 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
}
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
ap_sta_remove(hapd, sta);
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
}
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_ASSOC;
ap_sta_remove(hapd, sta);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
__func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DISASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
mlme_disassociate_indication(hapd, sta, reason);
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
eloop_register_timeout(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
ap_sta_disassoc_cb_timeout, hapd, sta);
}
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
ap_sta_remove(hapd, sta);
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
}
@ -522,18 +609,45 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
ap_sta_remove(hapd, sta);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
__func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
mlme_deauthenticate_indication(hapd, sta, reason);
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
eloop_register_timeout(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
ap_sta_deauth_cb_timeout, hapd, sta);
}
#ifdef CONFIG_WPS
int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx)
{
if (sta && (sta->flags & WLAN_STA_WPS)) {
ap_sta_deauthenticate(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
__func__, MAC2STR(sta->addr));
return 1;
}
return 0;
}
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
@ -636,7 +750,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
ret = hapd->drv.set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
if (ret < 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
@ -686,8 +800,9 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
ap_check_sa_query_timeout(hapd, sta))
return;
nbuf = os_realloc(sta->sa_query_trans_id,
(sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (sta->sa_query_count == 0) {
@ -709,9 +824,7 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
#ifdef NEED_AP_MLME
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
#endif /* NEED_AP_MLME */
}
@ -732,6 +845,73 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_IEEE80211W */
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
const u8 *dev_addr = NULL;
#ifdef CONFIG_P2P
u8 addr[ETH_ALEN];
#endif /* CONFIG_P2P */
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
if (sta->p2p_ie != NULL &&
p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
dev_addr = addr;
} else
dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
if (authorized) {
if (dev_addr)
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
MACSTR, MAC2STR(sta->addr));
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED MACSTR " p2p_dev_addr="
MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
sta->flags |= WLAN_STA_AUTHORIZED;
} else {
if (dev_addr)
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
MACSTR " p2p_dev_addr=" MACSTR,
MAC2STR(sta->addr), MAC2STR(dev_addr));
else
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
MACSTR, MAC2STR(sta->addr));
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
else if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED MACSTR,
MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_AUTHORIZED;
}
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
sta->addr, authorized, dev_addr);
}
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason)
{
@ -740,12 +920,52 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
sta = ap_get_sta(hapd, addr);
if (addr)
hapd->drv.sta_deauth(hapd, addr, reason);
hostapd_drv_sta_deauth(hapd, addr, reason);
if (sta == NULL)
return;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
ap_sta_set_authorized(hapd, sta, 0);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
__func__, MAC2STR(sta->addr),
AP_MAX_INACTIVITY_AFTER_DEAUTH);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
sta->timeout_next = STA_REMOVE;
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
eloop_register_timeout(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
ap_sta_deauth_cb_timeout, hapd, sta);
}
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
{
if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
return;
}
sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
ap_sta_deauth_cb_timeout(hapd, sta);
}
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
{
if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
return;
}
sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
ap_sta_disassoc_cb_timeout(hapd, sta);
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef STA_INFO_H
@ -31,6 +25,12 @@
#define WLAN_STA_WPS BIT(12)
#define WLAN_STA_MAYBE_WPS BIT(13)
#define WLAN_STA_WDS BIT(14)
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
/* Maximum number of supported rates (from both Supported Rates and Extended
@ -48,6 +48,7 @@ struct sta_info {
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
int supported_rates_len;
u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
@ -55,6 +56,7 @@ struct sta_info {
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
u16 auth_alg;
u8 previous_ap[6];
@ -63,6 +65,9 @@ struct sta_info {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
} timeout_next;
u16 deauth_reason;
u16 disassoc_reason;
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
@ -90,8 +95,14 @@ struct sta_info {
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
char *identity; /* User-Name from RADIUS */
char *radius_cui; /* Chargeable-User-Identity from RADIUS */
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
@ -103,7 +114,22 @@ struct sta_info {
struct os_time sa_query_start;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_INTERWORKING
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
struct gas_dialog_info *gas_dialog;
u8 gas_dialog_next;
#endif /* CONFIG_INTERWORKING */
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
struct os_time connected_time;
#ifdef CONFIG_SAE
enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
u16 sae_send_confirm;
#endif /* CONFIG_SAE */
};
@ -111,7 +137,7 @@ struct sta_info {
* passed since last received frame from the station, a nullfunc data frame is
* sent to the station. If this frame is not acknowledged and no other frames
* have been received, the station will be disassociated after
* AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
* AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
#define AP_MAX_INACTIVITY (5 * 60)
#define AP_DISASSOC_DELAY (1)
@ -132,7 +158,6 @@ int ap_for_each_sta(struct hostapd_data *hapd,
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
@ -144,6 +169,10 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
#ifdef CONFIG_WPS
int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx);
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
@ -152,4 +181,14 @@ int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
void ap_sta_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
static inline int ap_sta_is_authorized(struct sta_info *sta)
{
return sta->flags & WLAN_STA_AUTHORIZED;
}
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */

View File

@ -1,15 +1,9 @@
/*
* hostapd / TKIP countermeasures
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -17,10 +11,12 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "radius/radius.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_mlme.h"
#include "wpa_auth.h"
#include "ap_drv_ops.h"
#include "tkip_countermeasures.h"
@ -29,7 +25,7 @@ static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
{
struct hostapd_data *hapd = eloop_ctx;
hapd->tkip_countermeasures = 0;
hapd->drv.set_countermeasures(hapd, 0);
hostapd_drv_set_countermeasures(hapd, 0);
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
}
@ -44,24 +40,36 @@ static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
wpa_auth_countermeasures_start(hapd->wpa_auth);
hapd->tkip_countermeasures = 1;
hapd->drv.set_countermeasures(hapd, 1);
hostapd_drv_set_countermeasures(hapd, 1);
wpa_gtk_rekey(hapd->wpa_auth);
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
hapd, NULL);
for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
hapd->drv.sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_AUTHORIZED);
hapd->drv.sta_remove(hapd, sta->addr);
while ((sta = hapd->sta_list)) {
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
if (sta->flags & WLAN_STA_AUTH) {
mlme_deauthenticate_indication(
hapd, sta,
WLAN_REASON_MICHAEL_MIC_FAILURE);
}
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
ap_free_sta(hapd, sta);
}
}
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
{
time_t now;
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
}
int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
struct os_time now;
int ret = 0;
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
@ -77,17 +85,21 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
"MLME-MICHAELMICFAILURE.indication "
"for not associated STA (" MACSTR
") ignored", MAC2STR(addr));
return;
return ret;
}
}
time(&now);
if (now > hapd->michael_mic_failure + 60) {
os_get_time(&now);
if (now.sec > hapd->michael_mic_failure + 60) {
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
if (hapd->michael_mic_failures > 1)
if (hapd->michael_mic_failures > 1) {
ieee80211_tkip_countermeasures_start(hapd);
ret = 1;
}
}
hapd->michael_mic_failure = now;
hapd->michael_mic_failure = now.sec;
return ret;
}

View File

@ -1,20 +1,15 @@
/*
* hostapd / TKIP countermeasures
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef TKIP_COUNTERMEASURES_H
#define TKIP_COUNTERMEASURES_H
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
#endif /* TKIP_COUNTERMEASURES_H */

View File

@ -2,14 +2,8 @@
* AP mode helper functions
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
@ -22,13 +16,15 @@
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *ie, size_t ie_len),
const u8 *da, const u8 *bssid,
const u8 *ie, size_t ie_len,
int ssi_signal),
void *ctx)
{
struct hostapd_probereq_cb *n;
n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
sizeof(struct hostapd_probereq_cb));
n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
sizeof(struct hostapd_probereq_cb));
if (n == NULL)
return -1;
@ -82,7 +78,8 @@ void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
struct prune_data data;
data.hapd = hapd;
data.addr = addr;
if (hapd->iface->for_each_interface)
hapd->iface->for_each_interface(hapd->iface->interfaces,
prune_associations, &data);
if (hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface)
hapd->iface->interfaces->for_each_interface(
hapd->iface->interfaces, prune_associations, &data);
}

View File

@ -19,7 +19,9 @@
#include "utils/common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "vlan_init.h"
#include "vlan_util.h"
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@ -334,7 +336,9 @@ static int br_getnumports(const char *br_name)
}
static int vlan_rem(const char *if_name)
#ifndef CONFIG_VLAN_NETLINK
int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@ -377,7 +381,7 @@ static int vlan_rem(const char *if_name)
returns 1 if the interface already exists
returns 0 otherwise
*/
static int vlan_add(const char *if_name, int vid)
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@ -473,6 +477,8 @@ static int vlan_set_name_type(unsigned int name_type)
return 0;
}
#endif /* CONFIG_VLAN_NETLINK */
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
@ -480,6 +486,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@ -495,13 +502,22 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
ifconfig_up(br_name);
if (tagged_interface) {
if (vlan_naming ==
DYNAMIC_VLAN_NAMING_WITH_DEVICE)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"%s.%d", tagged_interface,
vlan->vlan_id);
else
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (!vlan_add(tagged_interface, vlan->vlan_id))
ifconfig_up(tagged_interface);
if (!vlan_add(tagged_interface, vlan->vlan_id,
vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN;
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
@ -526,6 +542,7 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
char br_name[IFNAMSIZ];
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
@ -540,8 +557,16 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
br_delif(br_name, vlan->ifname);
if (tagged_interface) {
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (vlan_naming ==
DYNAMIC_VLAN_NAMING_WITH_DEVICE)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"%s.%d", tagged_interface,
vlan->vlan_id);
else
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
ifconfig_down(vlan_ifname);
@ -681,7 +706,12 @@ full_dynamic_vlan_init(struct hostapd_data *hapd)
if (priv == NULL)
return NULL;
vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
#ifndef CONFIG_VLAN_NETLINK
vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
#endif /* CONFIG_VLAN_NETLINK */
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (priv->s < 0) {
@ -737,9 +767,10 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
* functions for setting up dynamic broadcast keys. */
for (i = 0; i < 4; i++) {
if (mssid->wep.key[i] &&
hapd->drv.set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
i == mssid->wep.idx, NULL, 0,
mssid->wep.key[i], mssid->wep.len[i])) {
hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
i == mssid->wep.idx, NULL, 0,
mssid->wep.key[i], mssid->wep.len[i]))
{
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
"encryption for dynamic VLAN");
return -1;
@ -755,7 +786,7 @@ static int vlan_dynamic_add(struct hostapd_data *hapd,
{
while (vlan) {
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
if (hapd->drv.vlan_if_add(hapd, vlan->ifname)) {
if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
if (errno != EEXIST) {
wpa_printf(MSG_ERROR, "VLAN: Could "
"not add VLAN %s: %s",
@ -785,7 +816,7 @@ static void vlan_dynamic_remove(struct hostapd_data *hapd,
next = vlan->next;
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
hapd->drv.vlan_if_remove(hapd, vlan->ifname)) {
hostapd_vlan_if_remove(hapd, vlan->ifname)) {
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
"iface: %s: %s",
vlan->ifname, strerror(errno));
@ -859,7 +890,7 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
pos);
os_free(ifname);
if (hapd->drv.vlan_if_add(hapd, n->ifname)) {
if (hostapd_vlan_if_add(hapd, n->ifname)) {
os_free(n);
return NULL;
}
@ -897,7 +928,7 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
return 1;
if (vlan->dynamic_vlan == 0)
hapd->drv.vlan_if_remove(hapd, vlan->ifname);
hostapd_vlan_if_remove(hapd, vlan->ifname);
return 0;
}

View File

@ -0,0 +1,177 @@
/*
* hostapd / VLAN netlink api
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/if_vlan.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include "utils/common.h"
#include "utils/eloop.h"
#include "hostapd.h"
#include "vlan_util.h"
/*
* Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
* tagged interface 'if_name'.
*
* returns -1 on error
* returns 1 if the interface already exists
* returns 0 otherwise
*/
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
int if_idx = 0;
wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
"vlan_if_name=%s)", if_name, vid, vlan_if_name);
if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
if_name);
return -1;
}
if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
vlan_if_name);
return -1;
}
handle = nl_socket_alloc();
if (!handle) {
wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
goto vlan_add_error;
}
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
goto vlan_add_error;
}
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
cache = NULL;
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
goto vlan_add_error;
}
if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
/* link does not exist */
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
if_name);
goto vlan_add_error;
}
if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
/* link does exist */
rtnl_link_put(rlink);
rlink = NULL;
wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
vlan_if_name);
ret = 1;
goto vlan_add_error;
}
rlink = rtnl_link_alloc();
if (!rlink) {
wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
goto vlan_add_error;
}
if (rtnl_link_set_type(rlink, "vlan") < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
goto vlan_add_error;
}
rtnl_link_set_link(rlink, if_idx);
rtnl_link_set_name(rlink, vlan_if_name);
if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
goto vlan_add_error;
}
if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
"vlan %d on %s (%d)",
vlan_if_name, vid, if_name, if_idx);
goto vlan_add_error;
}
ret = 0;
vlan_add_error:
if (rlink)
rtnl_link_put(rlink);
if (cache)
nl_cache_free(cache);
if (handle)
nl_socket_free(handle);
return ret;
}
int vlan_rem(const char *if_name)
{
int ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
handle = nl_socket_alloc();
if (!handle) {
wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
goto vlan_rem_error;
}
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
goto vlan_rem_error;
}
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
cache = NULL;
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
goto vlan_rem_error;
}
if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
/* link does not exist */
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
if_name);
goto vlan_rem_error;
}
if (rtnl_link_delete(handle, rlink) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
if_name);
goto vlan_rem_error;
}
ret = 0;
vlan_rem_error:
if (rlink)
rtnl_link_put(rlink);
if (cache)
nl_cache_free(cache);
if (handle)
nl_socket_free(handle);
return ret;
}

View File

@ -0,0 +1,15 @@
/*
* hostapd / VLAN netlink api
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef VLAN_UTIL_H
#define VLAN_UTIL_H
int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
int vlan_rem(const char *if_name);
#endif /* VLAN_UTIL_H */

View File

@ -23,6 +23,7 @@
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "wmm.h"
@ -71,9 +72,12 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
wmm->version = WMM_VERSION;
wmm->qos_info = hapd->parameter_set_count & 0xf;
if (hapd->conf->wmm_uapsd)
if (hapd->conf->wmm_uapsd &&
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
wmm->qos_info |= 0x80;
wmm->reserved = 0;
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wmm_ac_parameter *ac = &wmm->ac[e];
@ -94,9 +98,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
}
/* This function is called when a station sends an association request with
* WMM info element. The function returns zero on success or non-zero on any
* error in WMM element. eid does not include Element ID and Length octets. */
/*
* This function is called when a station sends an association request with
* WMM info element. The function returns 1 on success or 0 on any error in WMM
* element. eid does not include Element ID and Length octets.
*/
int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
{
struct wmm_information_element *wmm;
@ -106,7 +112,7 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
if (len < sizeof(struct wmm_information_element)) {
wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
(unsigned long) len);
return -1;
return 0;
}
wmm = (struct wmm_information_element *) eid;
@ -117,10 +123,10 @@ int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
wmm->version != WMM_VERSION) {
wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
return -1;
return 0;
}
return 0;
return 1;
}
@ -150,7 +156,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
if (hapd->drv.send_mgmt_frame(hapd, m, len) < 0)
if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
perror("wmm_send_action: send");
}

271
contrib/wpa/src/ap/wnm_ap.c Normal file
View File

@ -0,0 +1,271 @@
/*
* hostapd - WNM
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
#include "ap/wpa_auth.h"
#include "wnm_ap.h"
#define MAX_TFS_IE_LEN 1024
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
u8 *buf, u16 *buf_len, enum wnm_oper oper)
{
wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
}
/* set the TFS IE to driver */
static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
u8 *buf, u16 *buf_len, enum wnm_oper oper)
{
wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
}
/* MLME-SLEEPMODE.response */
static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
const u8 *addr, u8 dialog_token,
u8 action_type, u16 intval)
{
struct ieee80211_mgmt *mgmt;
int res;
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie;
u8 wnmsleep_ie_len;
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return -EINVAL;
}
/* WNM-Sleep Mode IE */
os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
wnmsleep_ie.len = wnmsleep_ie_len - 2;
wnmsleep_ie.action_type = action_type;
wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
wnmsleep_ie.intval = intval;
/* TFS IE(s) */
wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
if (wnmtfs_ie == NULL)
return -1;
if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
tfs_oper)) {
wnmtfs_ie_len = 0;
os_free(wnmtfs_ie);
wnmtfs_ie = NULL;
}
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
return -1;
}
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP;
mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
/* add key data if MFP is enabled */
if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
action_type != WNM_SLEEP_MODE_EXIT) {
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
} else {
gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0) {
os_free(wnmtfs_ie);
os_free(mgmt);
return -1;
}
igtk_elem_len = res;
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
gtk_elem_len + igtk_elem_len);
}
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
if (wnmtfs_ie)
os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
mgmt->da, &mgmt->u.action.category, len);
if (!res) {
wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
"frame");
/* when entering wnmsleep
* 1. pause the node in driver
* 2. mark the node so that AP won't update GTK/IGTK during
* WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
addr, NULL, NULL);
wpa_set_wnmsleep(sta->wpa_sm, 1);
}
/* when exiting wnmsleep
* 1. unmark the node
* 2. start GTK/IGTK update if MFP is not used
* 3. unpause the node in driver
*/
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
wnmsleep_ie.status ==
WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
if (!wpa_auth_uses_mfp(sta->wpa_sm))
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
}
} else
wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
os_free(wnmtfs_ie);
os_free(mgmt);
return res;
}
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm, int len)
{
/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
const u8 *pos = frm;
u8 dialog_token;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Req IE (assuming consecutive) */
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
dialog_token = *pos++;
while (pos + 1 < frm + len) {
u8 ie_len = pos[1];
if (pos + 2 + ie_len > frm + len)
break;
if (*pos == WLAN_EID_WNMSLEEP)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
tfsreq_ie_start = (u8 *) pos;
tfsreq_ie_end = (u8 *) pos;
} else
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
*pos);
pos += ie_len + 2;
}
if (!wnmsleep_ie) {
wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
return;
}
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
tfsreq_ie_start && tfsreq_ie_end &&
tfsreq_ie_end - tfsreq_ie_start >= 0) {
tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
tfsreq_ie_start;
wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
/* pass the TFS Req IE(s) to driver for processing */
if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
&tfsreq_ie_len,
WNM_SLEEP_TFS_REQ_IE_SET))
wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
}
ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
wnmsleep_ie->action_type,
wnmsleep_ie->intval);
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
/* clear the tfs after sending the resp frame */
ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
&tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
}
}
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
struct rx_action *action)
{
if (action->len < 1 || action->data == NULL)
return -1;
switch (action->data[0]) {
case WNM_BSS_TRANS_MGMT_QUERY:
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
/* TODO */
return -1;
case WNM_BSS_TRANS_MGMT_RESP:
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
"Response");
/* TODO */
return -1;
case WNM_SLEEP_MODE_REQ:
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
action->len - 1);
return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
action->data[0], MAC2STR(action->sa));
return -1;
}

View File

@ -0,0 +1,17 @@
/*
* IEEE 802.11v WNM related functions and structures
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WNM_AP_H
#define WNM_AP_H
struct rx_action;
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
struct rx_action *action);
#endif /* WNM_AP_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,8 @@
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_AUTH_H
@ -143,7 +137,9 @@ struct wpa_auth_config {
int peerkey;
int wmm_enabled;
int wmm_uapsd;
int disable_pmksa_caching;
int okc;
int tx_status;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
@ -160,7 +156,10 @@ struct wpa_auth_config {
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
int disable_gtk;
int ap_mlme;
};
typedef enum {
@ -178,7 +177,7 @@ struct wpa_auth_callbacks {
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
void (*mic_failure_report)(void *ctx, const u8 *addr);
int (*mic_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@ -199,12 +198,15 @@ struct wpa_auth_callbacks {
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
struct wpa_auth_callbacks *cb);
int wpa_init_keys(struct wpa_authenticator *wpa_auth);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
@ -259,6 +261,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
#ifdef CONFIG_IEEE80211R
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
@ -278,4 +282,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
#endif /* WPA_AUTH_H */

View File

@ -2,14 +2,8 @@
* hostapd - IEEE 802.11r - Fast BSS Transition
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -18,38 +12,16 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
#include "crypto/random.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wmm.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
#include "wpa_auth_ie.h"
#ifdef CONFIG_IEEE80211R
struct wpa_ft_ies {
const u8 *mdie;
size_t mdie_len;
const u8 *ftie;
size_t ftie_len;
const u8 *r1kh_id;
const u8 *gtk;
size_t gtk_len;
const u8 *r0kh_id;
size_t r0kh_id_len;
const u8 *rsn;
size_t rsn_len;
const u8 *rsn_pmkid;
const u8 *ric;
size_t ric_len;
};
static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
struct wpa_ft_ies *parse);
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
@ -80,6 +52,19 @@ wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
}
static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
if (wpa_auth->cb.add_tspec == NULL) {
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
return -1;
}
return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
tspec_ielen);
}
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
@ -91,7 +76,9 @@ int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
*pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
pos += MOBILITY_DOMAIN_ID_LEN;
capab = RSN_FT_CAPAB_FT_OVER_DS;
capab = 0;
if (conf->ft_over_ds)
capab |= RSN_FT_CAPAB_FT_OVER_DS;
*pos++ = capab;
return pos - buf;
@ -334,7 +321,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
/* aes_wrap() does not support inplace encryption, so use a temporary
* buffer for the data. */
if (os_get_random(f.nonce, sizeof(f.nonce))) {
if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
"nonce");
return -1;
@ -497,7 +484,8 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
#endif /* CONFIG_IEEE80211W */
static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
{
struct ieee802_11_elems parse;
@ -530,7 +518,7 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
}
#ifdef NEED_AP_MLME
if (parse.wmm_tspec) {
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
struct wmm_tspec_element *tspec;
int res;
@ -567,13 +555,35 @@ static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
}
#endif /* NEED_AP_MLME */
if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
struct wmm_tspec_element *tspec;
int res;
tspec = (struct wmm_tspec_element *) pos;
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
sizeof(*tspec));
if (res >= 0) {
if (res)
rdie->status_code = host_to_le16(res);
else {
/* TSPEC accepted; include updated TSPEC in
* response */
rdie->descr_count = 1;
pos += sizeof(*tspec);
}
return pos;
}
}
wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
return pos;
}
static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
const u8 *ric, size_t ric_len)
{
const u8 *rpos, *start;
const struct rsn_rdie *rdie;
@ -595,7 +605,7 @@ static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
break;
rpos += 2 + rpos[1];
}
pos = wpa_ft_process_rdie(pos, end, rdie->id,
pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
rdie->descr_count,
start, rpos - start);
}
@ -704,7 +714,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
ric_start = pos;
if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
parse.ric_len);
if (auth_alg == WLAN_AUTH_FT)
_ftie->mic_control[1] +=
ieee802_11_ie_count(ric_start,
@ -725,143 +736,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
}
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
struct wpa_ft_ies *parse)
{
const u8 *end, *pos;
parse->ftie = ie;
parse->ftie_len = ie_len;
pos = ie + sizeof(struct rsn_ftie);
end = ie + ie_len;
while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
switch (pos[0]) {
case FTIE_SUBELEM_R1KH_ID:
if (pos[1] != FT_R1KH_ID_LEN) {
wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
"length in FTIE: %d", pos[1]);
return -1;
}
parse->r1kh_id = pos + 2;
break;
case FTIE_SUBELEM_GTK:
parse->gtk = pos + 2;
parse->gtk_len = pos[1];
break;
case FTIE_SUBELEM_R0KH_ID:
if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
"length in FTIE: %d", pos[1]);
return -1;
}
parse->r0kh_id = pos + 2;
parse->r0kh_id_len = pos[1];
break;
}
pos += 2 + pos[1];
}
return 0;
}
static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
struct wpa_ft_ies *parse)
{
const u8 *end, *pos;
struct wpa_ie_data data;
int ret;
const struct rsn_ftie *ftie;
int prot_ie_count = 0;
os_memset(parse, 0, sizeof(*parse));
if (ies == NULL)
return 0;
pos = ies;
end = ies + ies_len;
while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
switch (pos[0]) {
case WLAN_EID_RSN:
parse->rsn = pos + 2;
parse->rsn_len = pos[1];
ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
parse->rsn_len + 2,
&data);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to parse "
"RSN IE: %d", ret);
return -1;
}
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
break;
case WLAN_EID_MOBILITY_DOMAIN:
parse->mdie = pos + 2;
parse->mdie_len = pos[1];
break;
case WLAN_EID_FAST_BSS_TRANSITION:
if (pos[1] < sizeof(*ftie))
return -1;
ftie = (const struct rsn_ftie *) (pos + 2);
prot_ie_count = ftie->mic_control[1];
if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
return -1;
break;
case WLAN_EID_RIC_DATA:
if (parse->ric == NULL)
parse->ric = pos;
}
pos += 2 + pos[1];
}
if (prot_ie_count == 0)
return 0; /* no MIC */
/*
* Check that the protected IE count matches with IEs included in the
* frame.
*/
if (parse->rsn)
prot_ie_count--;
if (parse->mdie)
prot_ie_count--;
if (parse->ftie)
prot_ie_count--;
if (prot_ie_count < 0) {
wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
"the protected IE count");
return -1;
}
if (prot_ie_count == 0 && parse->ric) {
wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
"included in protected IE count");
return -1;
}
/* Determine the end of the RIC IE(s) */
pos = parse->ric;
while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
prot_ie_count) {
prot_ie_count--;
pos += 2 + pos[1];
}
parse->ric_len = pos - parse->ric;
if (prot_ie_count) {
wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
"frame", (int) prot_ie_count);
return -1;
}
return 0;
}
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
@ -880,13 +754,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
int klen;
/* MLME-SETKEYS.request(PTK) */
if (sm->pairwise == WPA_CIPHER_TKIP) {
alg = WPA_ALG_TKIP;
klen = 32;
} else if (sm->pairwise == WPA_CIPHER_CCMP) {
alg = WPA_ALG_CCMP;
klen = 16;
} else {
alg = wpa_cipher_to_alg(sm->pairwise);
klen = wpa_cipher_key_len(sm->pairwise);
if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
"PTK configuration", sm->pairwise);
return;
@ -997,7 +867,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
sm->pmk_r1_name_valid = 1;
os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) {
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
"ANonce");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@ -1008,7 +878,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48;
ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name,
(u8 *) &sm->PTK, ptk_len, ptk_name);
@ -1204,7 +1074,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
count = 3;
if (parse.ric)
count++;
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
if (ftie->mic_control[1] != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@ -1224,8 +1094,16 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
if (os_memcmp(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
parse.ftie - 2, parse.ftie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
parse.rsn - 2, parse.rsn_len + 2);
return WLAN_STATUS_INVALID_FTIE;
}

View File

@ -1,15 +1,9 @@
/*
* hostapd / WPA authenticator glue code
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -29,17 +23,13 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "wpa_auth.h"
#ifdef CONFIG_IEEE80211R
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len);
#endif /* CONFIG_IEEE80211R */
#include "wpa_auth_glue.h"
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct wpa_auth_config *wconf)
{
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
@ -54,6 +44,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->peerkey = conf->peerkey;
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
@ -77,7 +68,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->r0kh_list = conf->r0kh_list;
wconf->r1kh_list = conf->r1kh_list;
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
#endif /* CONFIG_HS20 */
}
@ -117,10 +112,10 @@ static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
}
static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
michael_mic_failure(hapd, addr, 0);
return michael_mic_failure(hapd, addr, 0);
}
@ -188,7 +183,24 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
return hostapd_get_psk(hapd->conf, addr, prev_psk);
struct sta_info *sta = ap_get_sta(hapd, addr);
const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
* logic list (all hostapd_get_psk; all sta->psk)
*/
if (sta && sta->psk && !psk) {
struct hostapd_sta_wpa_psk_short *pos;
psk = sta->psk->psk;
for (pos = sta->psk; pos; pos = pos->next) {
if (pos->psk == prev_psk) {
psk = pos->next ? pos->next->psk : NULL;
break;
}
}
}
return psk;
}
@ -230,8 +242,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
return -1;
}
return hapd->drv.set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
key, key_len);
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
key, key_len);
}
@ -248,7 +260,15 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
int encrypt)
{
struct hostapd_data *hapd = ctx;
return hapd->drv.send_eapol(hapd, addr, data, data_len, encrypt);
struct sta_info *sta;
u32 flags = 0;
sta = ap_get_sta(hapd, addr);
if (sta)
flags = hostapd_sta_flags_to_drv(sta->flags);
return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
encrypt, flags);
}
@ -291,12 +311,13 @@ static int hostapd_wpa_auth_for_each_auth(
{
struct hostapd_data *hapd = ctx;
struct wpa_auth_iface_iter_data data;
if (hapd->iface->for_each_interface == NULL)
if (hapd->iface->interfaces == NULL ||
hapd->iface->interfaces->for_each_interface == NULL)
return -1;
data.cb = cb;
data.cb_ctx = cb_ctx;
return hapd->iface->for_each_interface(hapd->iface->interfaces,
wpa_auth_iface_iter, &data);
return hapd->iface->interfaces->for_each_interface(
hapd->iface->interfaces, wpa_auth_iface_iter, &data);
}
@ -327,8 +348,9 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
MAC2STR(idata->src_hapd->own_addr),
idata->src_hapd->conf->iface,
MAC2STR(hapd->own_addr), hapd->conf->iface);
hostapd_rrb_receive(hapd, idata->src_hapd->own_addr,
idata->data, idata->data_len);
wpa_ft_rrb_rx(hapd->wpa_auth,
idata->src_hapd->own_addr,
idata->data, idata->data_len);
return 1;
}
}
@ -343,18 +365,21 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
const u8 *data, size_t data_len)
{
struct hostapd_data *hapd = ctx;
struct l2_ethhdr *buf;
int ret;
#ifdef CONFIG_IEEE80211R
if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
int res;
struct wpa_auth_ft_iface_iter_data idata;
idata.src_hapd = hapd;
idata.dst = dst;
idata.data = data;
idata.data_len = data_len;
res = hapd->iface->for_each_interface(hapd->iface->interfaces,
hostapd_wpa_auth_ft_iter,
&idata);
res = hapd->iface->interfaces->for_each_interface(
hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
&idata);
if (res == 1)
return data_len;
}
@ -366,7 +391,18 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
data, data_len);
if (hapd->l2 == NULL)
return -1;
return l2_packet_send(hapd->l2, dst, proto, data, data_len);
buf = os_malloc(sizeof(*buf) + data_len);
if (buf == NULL)
return -1;
os_memcpy(buf->h_dest, dst, ETH_ALEN);
os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
buf->h_proto = host_to_be16(proto);
os_memcpy(buf + 1, data, data_len);
ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
sizeof(*buf) + data_len);
os_free(buf);
return ret;
}
@ -396,7 +432,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
res = hapd->drv.send_mgmt_frame(hapd, (u8 *) m, mlen);
res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
os_free(m);
return res;
}
@ -408,6 +444,9 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
@ -431,7 +470,22 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
struct hostapd_data *hapd = ctx;
wpa_ft_rrb_rx(hapd->wpa_auth, src_addr, buf, len);
struct l2_ethhdr *ethhdr;
if (len < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) buf;
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
len - sizeof(*ethhdr));
}
static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
struct hostapd_data *hapd = ctx;
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
}
#endif /* CONFIG_IEEE80211R */
@ -445,6 +499,10 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = hapd;
cb.logger = hostapd_wpa_auth_logger;
@ -463,6 +521,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
cb.add_sta = hostapd_wpa_auth_add_sta;
cb.add_tspec = hostapd_wpa_auth_add_tspec;
#endif /* CONFIG_IEEE80211R */
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
if (hapd->wpa_auth == NULL) {
@ -494,7 +553,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
hapd->conf->bridge :
hapd->conf->iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 0);
hostapd_rrb_receive, hapd, 1);
if (hapd->l2 == NULL &&
(hapd->driver == NULL ||
hapd->driver->send_ether == NULL)) {
@ -520,6 +579,7 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
ieee80211_tkip_countermeasures_deinit(hapd);
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);

View File

@ -2,14 +2,8 @@
* hostapd / WPA authenticator glue code
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_AUTH_GLUE_H

View File

@ -2,14 +2,8 @@
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_AUTH_I_H
@ -69,10 +63,11 @@ struct wpa_state_machine {
Boolean pairwise_set;
int keycount;
Boolean Pair;
struct {
struct wpa_key_replay_counter {
u8 counter[WPA_REPLAY_COUNTER_LEN];
Boolean valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES];
} key_replay[RSNA_MAX_EAPOL_RETRIES],
prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
Boolean PTKRequest; /* not in IEEE 802.11i state machine */
Boolean has_GTK;
@ -86,10 +81,13 @@ struct wpa_state_machine {
unsigned int pending_deinit:1;
unsigned int started:1;
unsigned int mgmt_frame_prot:1;
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
unsigned int is_wnmsleep:1;
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
@ -120,6 +118,8 @@ struct wpa_state_machine {
* message 2/4 */
u8 *assoc_resp_ftie;
#endif /* CONFIG_IEEE80211R */
int pending_1_of_4_timeout;
};
@ -145,6 +145,8 @@ struct wpa_group {
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
Boolean changed;
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN];
int GN_igtk, GM_igtk;

View File

@ -2,14 +2,8 @@
* hostapd - WPA/RSN IE and KDE definitions
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
@ -25,11 +19,17 @@
#include "wpa_auth_i.h"
#ifdef CONFIG_RSN_TESTING
int rsn_testing = 0;
#endif /* CONFIG_RSN_TESTING */
static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
struct wpa_ie_hdr *hdr;
int num_suites;
u8 *pos, *count;
u32 suite;
hdr = (struct wpa_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
@ -37,46 +37,25 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
if (conf->wpa_group == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
} else {
suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
num_suites = 0;
count = pos;
pos += 2;
if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->wpa_pairwise);
return -1;
}
pos += num_suites * WPA_SELECTOR_LEN;
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
@ -113,49 +92,48 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
int num_suites;
int num_suites, res;
u8 *pos, *count;
u16 capab;
u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
if (conf->wpa_group == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
} else {
suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
num_suites = 0;
count = pos;
pos += 2;
if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
#endif /* CONFIG_RSN_TESTING */
res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
num_suites += res;
pos += res * RSN_SELECTOR_LEN;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
@ -168,6 +146,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
count = pos;
pos += 2;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += RSN_SELECTOR_LEN;
@ -202,6 +188,26 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SAE */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
@ -227,6 +233,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing)
capab |= BIT(8) | BIT(14) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
WPA_PUT_LE16(pos, capab);
pos += 2;
@ -256,6 +266,29 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
/*
* Fill in any defined fields and add extra data to the end of
* the element.
*/
int pmkid_count_set = pmkid != NULL;
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
pmkid_count_set = 1;
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
}
os_memset(pos, 0x12, 17);
pos += 17;
}
#endif /* CONFIG_RSN_TESTING */
hdr->len = (pos - buf) - 2;
return pos - buf;
@ -277,8 +310,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos += res;
}
#ifdef CONFIG_IEEE80211R
if (wpa_auth->conf.wpa_key_mgmt &
(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
@ -322,114 +354,6 @@ u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
}
static int wpa_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
return WPA_CIPHER_WEP104;
return 0;
}
static int wpa_key_mgmt_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
return WPA_KEY_MGMT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
return WPA_KEY_MGMT_PSK;
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
return WPA_KEY_MGMT_WPA_NONE;
return 0;
}
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data)
{
const struct wpa_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
os_memset(data, 0, sizeof(*data));
data->pairwise_cipher = WPA_CIPHER_TKIP;
data->group_cipher = WPA_CIPHER_TKIP;
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
data->mgmt_group_cipher = 0;
if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
return -1;
hdr = (const struct wpa_ie_hdr *) wpa_ie;
if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
hdr->len != wpa_ie_len - 2 ||
RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
WPA_GET_LE16(hdr->version) != WPA_VERSION) {
return -2;
}
pos = (const u8 *) (hdr + 1);
left = wpa_ie_len - sizeof(*hdr);
if (left >= WPA_SELECTOR_LEN) {
data->group_cipher = wpa_selector_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
} else if (left > 0)
return -3;
if (left >= 2) {
data->pairwise_cipher = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN)
return -4;
for (i = 0; i < count; i++) {
data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1)
return -5;
if (left >= 2) {
data->key_mgmt = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN)
return -6;
for (i = 0; i < count; i++) {
data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1)
return -7;
if (left >= 2) {
data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
if (left > 0) {
return -8;
}
return 0;
}
struct wpa_auth_okc_iter_data {
struct rsn_pmksa_cache_entry *pmksa;
const u8 *aa;
@ -495,36 +419,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
selector = RSN_AUTH_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = RSN_CIPHER_SUITE_CCMP;
if (data.pairwise_cipher & WPA_CIPHER_CCMP)
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
data.pairwise_cipher);
if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
selector = RSN_CIPHER_SUITE_WEP104;
else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
selector = RSN_CIPHER_SUITE_WEP40;
else if (data.pairwise_cipher & WPA_CIPHER_NONE)
selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
selector = RSN_CIPHER_SUITE_CCMP;
if (data.group_cipher & WPA_CIPHER_CCMP)
selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
data.group_cipher);
if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
else if (data.group_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.group_cipher & WPA_CIPHER_WEP104)
selector = RSN_CIPHER_SUITE_WEP104;
else if (data.group_cipher & WPA_CIPHER_WEP40)
selector = RSN_CIPHER_SUITE_WEP40;
else if (data.group_cipher & WPA_CIPHER_NONE)
selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
} else {
res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
@ -536,30 +452,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = WPA_CIPHER_SUITE_TKIP;
if (data.pairwise_cipher & WPA_CIPHER_CCMP)
selector = WPA_CIPHER_SUITE_CCMP;
else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
selector = WPA_CIPHER_SUITE_TKIP;
else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
selector = WPA_CIPHER_SUITE_WEP104;
else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
selector = WPA_CIPHER_SUITE_WEP40;
else if (data.pairwise_cipher & WPA_CIPHER_NONE)
selector = WPA_CIPHER_SUITE_NONE;
selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
data.pairwise_cipher);
if (!selector)
selector = RSN_CIPHER_SUITE_TKIP;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
selector = WPA_CIPHER_SUITE_TKIP;
if (data.group_cipher & WPA_CIPHER_CCMP)
selector = WPA_CIPHER_SUITE_CCMP;
else if (data.group_cipher & WPA_CIPHER_TKIP)
selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
data.group_cipher);
if (!selector)
selector = WPA_CIPHER_SUITE_TKIP;
else if (data.group_cipher & WPA_CIPHER_WEP104)
selector = WPA_CIPHER_SUITE_WEP104;
else if (data.group_cipher & WPA_CIPHER_WEP40)
selector = WPA_CIPHER_SUITE_WEP40;
else if (data.group_cipher & WPA_CIPHER_NONE)
selector = WPA_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
}
if (res) {
@ -595,6 +497,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
else
@ -658,6 +566,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
else if (ciphers & WPA_CIPHER_GCMP)
sm->pairwise = WPA_CIPHER_GCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;

View File

@ -2,14 +2,8 @@
* hostapd - WPA/RSN IE and KDE definitions
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_AUTH_IE_H

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,9 @@
/*
* hostapd / WPS integration
* Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPS_HOSTAPD_H
@ -19,13 +13,14 @@
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf);
int hostapd_init_wps_complete(struct hostapd_data *hapd);
void hostapd_deinit_wps(struct hostapd_data *hapd);
void hostapd_update_wps(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd);
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
const char *uuid, const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
int hostapd_wps_cancel(struct hostapd_data *hapd);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen);
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
@ -33,6 +28,16 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
int timeout);
void hostapd_wps_update_ie(struct hostapd_data *hapd);
int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
const char *auth, const char *encr, const char *key);
int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
const struct wpabuf *data);
struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
int ndef);
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
#else /* CONFIG_WPS */
@ -46,6 +51,11 @@ static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
{
}
static inline int hostapd_init_wps_complete(struct hostapd_data *hapd)
{
return 0;
}
static inline void hostapd_update_wps(struct hostapd_data *hapd)
{
}
@ -57,7 +67,13 @@ static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
return 0;
}
static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd)
static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr)
{
return 0;
}
static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
{
return 0;
}

View File

@ -2,14 +2,8 @@
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DEFS_H
@ -32,6 +26,8 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
#define WPA_CIPHER_GCMP BIT(6)
#define WPA_CIPHER_SMS4 BIT(7)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@ -43,41 +39,73 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
#define WPA_KEY_MGMT_SAE BIT(10)
#define WPA_KEY_MGMT_FT_SAE BIT(11)
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return akm == WPA_KEY_MGMT_IEEE8021X ||
akm == WPA_KEY_MGMT_FT_IEEE8021X ||
akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_IEEE8021X_SHA256));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return akm == WPA_KEY_MGMT_PSK ||
akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_PSK_SHA256;
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_SAE));
}
static inline int wpa_key_mgmt_ft(int akm)
{
return akm == WPA_KEY_MGMT_FT_PSK ||
akm == WPA_KEY_MGMT_FT_IEEE8021X;
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sae(int akm)
{
return !!(akm & (WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sha256(int akm)
{
return akm == WPA_KEY_MGMT_PSK_SHA256 ||
akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256));
}
static inline int wpa_key_mgmt_wpa(int akm)
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm);
}
static inline int wpa_key_mgmt_wpa_any(int akm)
{
return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
}
static inline int wpa_key_mgmt_cckm(int akm)
{
return akm == WPA_KEY_MGMT_CCKM;
}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_PROTO_WAPI BIT(2)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
#define WPA_AUTH_ALG_SAE BIT(4)
enum wpa_alg {
@ -86,7 +114,10 @@ enum wpa_alg {
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
WPA_ALG_PMK
WPA_ALG_PMK,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK
};
/**
@ -97,7 +128,9 @@ enum wpa_cipher {
CIPHER_WEP40,
CIPHER_TKIP,
CIPHER_CCMP,
CIPHER_WEP104
CIPHER_WEP104,
CIPHER_GCMP,
CIPHER_SMS4
};
/**
@ -113,7 +146,12 @@ enum wpa_key_mgmt {
KEY_MGMT_FT_PSK,
KEY_MGMT_802_1X_SHA256,
KEY_MGMT_PSK_SHA256,
KEY_MGMT_WPS
KEY_MGMT_WPS,
KEY_MGMT_SAE,
KEY_MGMT_FT_SAE,
KEY_MGMT_WAPI_PSK,
KEY_MGMT_WAPI_CERT,
KEY_MGMT_CCKM
};
/**
@ -136,6 +174,15 @@ enum wpa_states {
*/
WPA_DISCONNECTED,
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
* This stat eis entered if the network interface is disabled, e.g.,
* due to rfkill. wpa_supplicant refuses any new operations that would
* use the radio until the interface has been enabled.
*/
WPA_INTERFACE_DISABLED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
@ -239,8 +286,9 @@ enum wpa_states {
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
MGMT_FRAME_PROTECTION_REQUIRED = 2
MGMT_FRAME_PROTECTION_REQUIRED = 2,
};
#define MGMT_FRAME_PROTECTION_DEFAULT 3
/**
* enum hostapd_hw_mode - Hardware mode
@ -249,7 +297,25 @@ enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
HOSTAPD_MODE_IEEE80211AD,
NUM_HOSTAPD_MODES
};
/**
* enum wpa_ctrl_req_type - Control interface request types
*/
enum wpa_ctrl_req_type {
WPA_CTRL_REQ_UNKNOWN,
WPA_CTRL_REQ_EAP_IDENTITY,
WPA_CTRL_REQ_EAP_PASSWORD,
WPA_CTRL_REQ_EAP_NEW_PASSWORD,
WPA_CTRL_REQ_EAP_PIN,
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
NUM_WPA_CTRL_REQS
};
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
#endif /* DEFS_H */

View File

@ -2,14 +2,8 @@
* EAPOL definitions shared between hostapd and wpa_supplicant
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef EAPOL_COMMON_H
@ -44,4 +38,44 @@ enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
#define IEEE8021X_REPLAY_COUNTER_LEN 8
#define IEEE8021X_KEY_SIGN_LEN 16
#define IEEE8021X_KEY_IV_LEN 16
#define IEEE8021X_KEY_INDEX_FLAG 0x80
#define IEEE8021X_KEY_INDEX_MASK 0x03
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
struct ieee802_1x_eapol_key {
u8 type;
/* Note: key_length is unaligned */
u8 key_length[2];
/* does not repeat within the life of the keying material used to
* encrypt the Key field; 64-bit NTP timestamp MAY be used here */
u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
u8 key_index; /* key flag in the most significant bit:
* 0 = broadcast (default key),
* 1 = unicast (key mapping key); key index is in the
* 7 least significant bits */
/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
* the key */
u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
/* followed by key: if packet body length = 44 + key length, then the
* key field (of key_length bytes) contains the key in encrypted form;
* if packet body length = 44, key field is absent and key_length
* represents the number of least significant octets from
* MS-MPPE-Send-Key attribute to be used as the keying material;
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#endif /* EAPOL_COMMON_H */

View File

@ -0,0 +1,273 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
* Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
static struct wpabuf *
gas_build_req(u8 action, u8 dialog_token, size_t size)
{
struct wpabuf *buf;
buf = wpabuf_alloc(100 + size);
if (buf == NULL)
return NULL;
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
wpabuf_put_u8(buf, action);
wpabuf_put_u8(buf, dialog_token);
return buf;
}
struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
{
return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
size);
}
struct wpabuf * gas_build_comeback_req(u8 dialog_token)
{
return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
}
static struct wpabuf *
gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
u8 more, u16 comeback_delay, size_t size)
{
struct wpabuf *buf;
buf = wpabuf_alloc(100 + size);
if (buf == NULL)
return NULL;
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
wpabuf_put_u8(buf, action);
wpabuf_put_u8(buf, dialog_token);
wpabuf_put_le16(buf, status_code);
if (action == WLAN_PA_GAS_COMEBACK_RESP)
wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
wpabuf_put_le16(buf, comeback_delay);
return buf;
}
struct wpabuf *
gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
size_t size)
{
return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
status_code, 0, 0, comeback_delay, size);
}
static struct wpabuf *
gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
u16 comeback_delay, size_t size)
{
return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
status_code, frag_id, more, comeback_delay,
size);
}
/**
* gas_add_adv_proto_anqp - Add an Advertisement Protocol element
* @buf: Buffer to which the element is added
* @query_resp_len_limit: Query Response Length Limit in units of 256 octets
* @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
*
*
* @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
* that the maximum limit is determined by the maximum allowable number of
* fragments in the GAS Query Response Fragment ID.
*/
static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
u8 pame_bi)
{
/* Advertisement Protocol IE */
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
wpabuf_put_u8(buf, 2); /* Length */
wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
(pame_bi ? 0x80 : 0));
/* Advertisement Protocol */
wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
}
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
{
struct wpabuf *buf;
buf = gas_build_initial_req(dialog_token, 4 + size);
if (buf == NULL)
return NULL;
gas_add_adv_proto_anqp(buf, 0, 0);
wpabuf_put(buf, 2); /* Query Request Length to be filled */
return buf;
}
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size)
{
struct wpabuf *buf;
buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
4 + size);
if (buf == NULL)
return NULL;
gas_add_adv_proto_anqp(buf, 0x7f, 0);
wpabuf_put(buf, 2); /* Query Response Length to be filled */
return buf;
}
struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
u16 status_code,
u16 comeback_delay,
struct wpabuf *payload)
{
struct wpabuf *buf;
buf = gas_anqp_build_initial_resp(dialog_token, status_code,
comeback_delay,
payload ? wpabuf_len(payload) : 0);
if (buf == NULL)
return NULL;
if (payload)
wpabuf_put_buf(buf, payload);
gas_anqp_set_len(buf);
return buf;
}
struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
u8 frag_id, u8 more,
u16 comeback_delay, size_t size)
{
struct wpabuf *buf;
buf = gas_build_comeback_resp(dialog_token, status_code,
frag_id, more, comeback_delay, 4 + size);
if (buf == NULL)
return NULL;
gas_add_adv_proto_anqp(buf, 0x7f, 0);
wpabuf_put(buf, 2); /* Query Response Length to be filled */
return buf;
}
struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
u16 status_code,
u8 frag_id, u8 more,
u16 comeback_delay,
struct wpabuf *payload)
{
struct wpabuf *buf;
buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
more, comeback_delay,
payload ? wpabuf_len(payload) : 0);
if (buf == NULL)
return NULL;
if (payload)
wpabuf_put_buf(buf, payload);
gas_anqp_set_len(buf);
return buf;
}
/**
* gas_anqp_set_len - Set Query Request/Response Length
* @buf: GAS message
*
* This function is used to update the Query Request/Response Length field once
* the payload has been filled.
*/
void gas_anqp_set_len(struct wpabuf *buf)
{
u8 action;
size_t offset;
u8 *len;
if (buf == NULL || wpabuf_len(buf) < 2)
return;
action = *(wpabuf_head_u8(buf) + 1);
switch (action) {
case WLAN_PA_GAS_INITIAL_REQ:
offset = 3 + 4;
break;
case WLAN_PA_GAS_INITIAL_RESP:
offset = 7 + 4;
break;
case WLAN_PA_GAS_COMEBACK_RESP:
offset = 8 + 4;
break;
default:
return;
}
if (wpabuf_len(buf) < offset + 2)
return;
len = wpabuf_mhead_u8(buf) + offset;
WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
}
/**
* gas_anqp_add_element - Add ANQP element header
* @buf: GAS message
* @info_id: ANQP Info ID
* Returns: Pointer to the Length field for gas_anqp_set_element_len()
*/
u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
{
wpabuf_put_le16(buf, info_id);
return wpabuf_put(buf, 2); /* Length to be filled */
}
/**
* gas_anqp_set_element_len - Update ANQP element Length field
* @buf: GAS message
* @len_pos: Length field position from gas_anqp_add_element()
*
* This function is called after the ANQP element payload has been added to the
* buffer.
*/
void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
{
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
}

View File

@ -0,0 +1,37 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
* Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef GAS_H
#define GAS_H
struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
u16 status_code,
u16 comeback_delay,
struct wpabuf *payload);
struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
u8 frag_id, u8 more,
u16 comeback_delay, size_t size);
struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
u16 status_code,
u8 frag_id, u8 more,
u16 comeback_delay,
struct wpabuf *payload);
void gas_anqp_set_len(struct wpabuf *buf);
u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
#endif /* GAS_H */

View File

@ -1,15 +1,9 @@
/*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
@ -75,7 +69,7 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->wmm_tspec_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "unknown WMM "
wpa_printf(MSG_EXCESSIVE, "unknown WMM "
"information element ignored "
"(subtype=%d len=%lu)",
pos[4], (unsigned long) elen);
@ -88,7 +82,33 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->wps_ie_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
"information element ignored "
"(type=%d len=%lu)",
pos[3], (unsigned long) elen);
return -1;
}
break;
case OUI_WFA:
switch (pos[3]) {
case P2P_OUI_TYPE:
/* Wi-Fi Alliance - P2P IE */
elems->p2p = pos;
elems->p2p_len = elen;
break;
case WFD_OUI_TYPE:
/* Wi-Fi Alliance - WFD IE */
elems->wfd = pos;
elems->wfd_len = elen;
break;
case HS20_INDICATION_OUI_TYPE:
/* Hotspot 2.0 */
elems->hs20 = pos;
elems->hs20_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
"(type=%d len=%lu)\n",
pos[3], (unsigned long) elen);
@ -103,18 +123,18 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->vendor_ht_cap_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
"(type=%d len=%lu)\n",
"(type=%d len=%lu)",
pos[3], (unsigned long) elen);
return -1;
}
break;
default:
wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
"element ignored (vendor OUI %02x:%02x:%02x "
"len=%lu)",
wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
"information element ignored (vendor OUI "
"%02x:%02x:%02x len=%lu)",
pos[0], pos[1], pos[2], (unsigned long) elen);
return -1;
}
@ -238,6 +258,36 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
case WLAN_EID_VHT_CAP:
elems->vht_capabilities = pos;
elems->vht_capabilities_len = elen;
break;
case WLAN_EID_VHT_OPERATION:
elems->vht_operation = pos;
elems->vht_operation_len = elen;
break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
elems->link_id = pos;
break;
case WLAN_EID_INTERWORKING:
elems->interworking = pos;
elems->interworking_len = elen;
break;
case WLAN_EID_EXT_CAPAB:
elems->ext_capab = pos;
elems->ext_capab_len = elen;
break;
case WLAN_EID_BSS_MAX_IDLE_PERIOD:
if (elen < 3)
break;
elems->bss_max_idle_period = pos;
break;
case WLAN_EID_SSID_LIST:
elems->ssid_list = pos;
elems->ssid_list_len = elen;
break;
default:
unknown++;
if (!show_errors)
@ -324,3 +374,115 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
return buf;
}
const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
{
u16 fc, type, stype;
/*
* PS-Poll frames are 16 bytes. All other frames are
* 24 bytes or longer.
*/
if (len < 16)
return NULL;
fc = le_to_host16(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
switch (type) {
case WLAN_FC_TYPE_DATA:
if (len < 24)
return NULL;
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
case WLAN_FC_FROMDS | WLAN_FC_TODS:
case WLAN_FC_TODS:
return hdr->addr1;
case WLAN_FC_FROMDS:
return hdr->addr2;
default:
return NULL;
}
case WLAN_FC_TYPE_CTRL:
if (stype != WLAN_FC_STYPE_PSPOLL)
return NULL;
return hdr->addr1;
case WLAN_FC_TYPE_MGMT:
return hdr->addr3;
default:
return NULL;
}
}
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val)
{
int num, v;
const char *pos;
struct hostapd_wmm_ac_params *ac;
/* skip 'wme_ac_' or 'wmm_ac_' prefix */
pos = name + 7;
if (os_strncmp(pos, "be_", 3) == 0) {
num = 0;
pos += 3;
} else if (os_strncmp(pos, "bk_", 3) == 0) {
num = 1;
pos += 3;
} else if (os_strncmp(pos, "vi_", 3) == 0) {
num = 2;
pos += 3;
} else if (os_strncmp(pos, "vo_", 3) == 0) {
num = 3;
pos += 3;
} else {
wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
return -1;
}
ac = &wmm_ac_params[num];
if (os_strcmp(pos, "aifs") == 0) {
v = atoi(val);
if (v < 1 || v > 255) {
wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
return -1;
}
ac->aifs = v;
} else if (os_strcmp(pos, "cwmin") == 0) {
v = atoi(val);
if (v < 0 || v > 12) {
wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
return -1;
}
ac->cwmin = v;
} else if (os_strcmp(pos, "cwmax") == 0) {
v = atoi(val);
if (v < 0 || v > 12) {
wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
return -1;
}
ac->cwmax = v;
} else if (os_strcmp(pos, "txop_limit") == 0) {
v = atoi(val);
if (v < 0 || v > 0xffff) {
wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
return -1;
}
ac->txop_limit = v;
} else if (os_strcmp(pos, "acm") == 0) {
v = atoi(val);
if (v < 0 || v > 1) {
wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
return -1;
}
ac->admission_control_mandatory = v;
} else {
wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
return -1;
}
return 0;
}

View File

@ -1,15 +1,9 @@
/*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IEEE802_11_COMMON_H
@ -39,7 +33,17 @@ struct ieee802_11_elems {
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
const u8 *vht_capabilities;
const u8 *vht_operation;
const u8 *vendor_ht_cap;
const u8 *p2p;
const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
const u8 *hs20;
const u8 *ext_capab;
const u8 *bss_max_idle_period;
const u8 *ssid_list;
u8 ssid_len;
u8 supp_rates_len;
@ -63,7 +67,15 @@ struct ieee802_11_elems {
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
u8 wfd_len;
u8 interworking_len;
u8 hs20_len;
u8 ext_capab_len;
u8 ssid_list_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@ -74,5 +86,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
struct ieee80211_hdr;
const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
struct hostapd_wmm_ac_params {
int cwmin;
int cwmax;
int aifs;
int txop_limit; /* in units of 32us */
int admission_control_mandatory;
};
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
#endif /* IEEE802_11_COMMON_H */

View File

@ -3,14 +3,8 @@
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef IEEE802_11_DEFS_H
@ -71,11 +65,18 @@
#define WLAN_FC_STYPE_CFPOLL 6
#define WLAN_FC_STYPE_CFACKPOLL 7
#define WLAN_FC_STYPE_QOS_DATA 8
#define WLAN_FC_STYPE_QOS_DATA_CFACK 9
#define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10
#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11
#define WLAN_FC_STYPE_QOS_NULL 12
#define WLAN_FC_STYPE_QOS_CFPOLL 14
#define WLAN_FC_STYPE_QOS_CFACKPOLL 15
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@ -95,6 +96,11 @@
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
#define WLAN_STATUS_SECURITY_DISABLED 5
#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
#define WLAN_STATUS_NOT_IN_SAME_BSS 7
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
@ -114,9 +120,10 @@
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
/* IEEE 802.11g */
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
#define WLAN_STATUS_R0KH_UNREACHABLE 28
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
/* IEEE 802.11w */
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
@ -141,6 +148,19 @@
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
#define WLAN_STATUS_REQ_REFUSED_HOME 64
#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
#define WLAN_STATUS_REQ_REFUSED_SSPN 67
#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
#define WLAN_STATUS_INVALID_RSNIE 72
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@ -168,6 +188,10 @@
#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34
/* Information Element IDs */
@ -202,10 +226,33 @@
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_WAPI 68
#define WLAN_EID_TIME_ADVERTISEMENT 69
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
#define WLAN_EID_SSID_LIST 84
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_TFS_REQ 91
#define WLAN_EID_TFS_RESP 92
#define WLAN_EID_WNMSLEEP 93
#define WLAN_EID_TIME_ZONE 98
#define WLAN_EID_LINK_ID 101
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_ROAMING_CONSORTIUM 111
#define WLAN_EID_EXT_CAPAB 127
#define WLAN_EID_CCKM 156
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194
#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
#define WLAN_EID_VENDOR_SPECIFIC 221
@ -219,7 +266,20 @@
#define WLAN_ACTION_FT 6
#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Public action codes */
#define WLAN_PA_20_40_BSS_COEX 0
#define WLAN_PA_VENDOR_SPECIFIC 9
#define WLAN_PA_GAS_INITIAL_REQ 10
#define WLAN_PA_GAS_INITIAL_RESP 11
#define WLAN_PA_GAS_COMEBACK_REQ 12
#define WLAN_PA_GAS_COMEBACK_RESP 13
#define WLAN_TDLS_DISCOVERY_RESPONSE 14
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
@ -227,11 +287,99 @@
#define WLAN_SA_QUERY_TR_ID_LEN 2
/* TDLS action codes */
#define WLAN_TDLS_SETUP_REQUEST 0
#define WLAN_TDLS_SETUP_RESPONSE 1
#define WLAN_TDLS_SETUP_CONFIRM 2
#define WLAN_TDLS_TEARDOWN 3
#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
#define WLAN_TDLS_PEER_PSM_REQUEST 7
#define WLAN_TDLS_PEER_PSM_RESPONSE 8
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
#define WLAN_TDLS_DISCOVERY_REQUEST 10
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
#define WLAN_TIMEOUT_KEY_LIFETIME 2
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
/* Interworking element (IEEE 802.11u) - Access Network Options */
#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
#define INTERWORKING_ANO_INTERNET 0x10
#define INTERWORKING_ANO_ASRA 0x20
#define INTERWORKING_ANO_ESR 0x40
#define INTERWORKING_ANO_UESA 0x80
#define INTERWORKING_ANT_PRIVATE 0
#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
#define INTERWORKING_ANT_FREE_PUBLIC 3
#define INTERWORKING_ANT_PERSONAL_DEVICE 4
#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
#define INTERWORKING_ANT_TEST 6
#define INTERWORKING_ANT_WILDCARD 15
/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
enum adv_proto_id {
ACCESS_NETWORK_QUERY_PROTOCOL = 0,
MIH_INFO_SERVICE = 1,
MIH_CMD_AND_EVENT_DISCOVERY = 2,
EMERGENCY_ALERT_SYSTEM = 3,
ADV_PROTO_VENDOR_SPECIFIC = 221
};
/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
enum anqp_info_id {
ANQP_QUERY_LIST = 256,
ANQP_CAPABILITY_LIST = 257,
ANQP_VENUE_NAME = 258,
ANQP_EMERGENCY_CALL_NUMBER = 259,
ANQP_NETWORK_AUTH_TYPE = 260,
ANQP_ROAMING_CONSORTIUM = 261,
ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
ANQP_NAI_REALM = 263,
ANQP_3GPP_CELLULAR_NETWORK = 264,
ANQP_AP_GEOSPATIAL_LOCATION = 265,
ANQP_AP_CIVIC_LOCATION = 266,
ANQP_AP_LOCATION_PUBLIC_URI = 267,
ANQP_DOMAIN_NAME = 268,
ANQP_EMERGENCY_ALERT_URI = 269,
ANQP_EMERGENCY_NAI = 271,
ANQP_VENDOR_SPECIFIC = 56797
};
/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
enum nai_realm_eap_auth_param {
NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
};
enum nai_realm_eap_auth_inner_non_eap {
NAI_REALM_INNER_NON_EAP_PAP = 1,
NAI_REALM_INNER_NON_EAP_CHAP = 2,
NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
};
enum nai_realm_eap_cred_type {
NAI_REALM_CRED_TYPE_SIM = 1,
NAI_REALM_CRED_TYPE_USIM = 2,
NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
NAI_REALM_CRED_TYPE_NONE = 8,
NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
};
#ifdef _MSC_VER
#pragma pack(push, 1)
@ -273,6 +421,7 @@ struct ieee80211_mgmt {
} STRUCT_PACKED auth;
struct {
le16 reason_code;
u8 variable[0];
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
@ -296,6 +445,7 @@ struct ieee80211_mgmt {
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
u8 variable[0];
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
@ -355,12 +505,58 @@ struct ieee80211_mgmt {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
u8 dialogtoken;
u8 variable[0];
} STRUCT_PACKED wnm_sleep_req;
struct {
u8 action;
u8 dialogtoken;
le16 keydata_len;
u8 variable[0];
} STRUCT_PACKED wnm_sleep_resp;
struct {
u8 action;
u8 variable[0];
} STRUCT_PACKED public_action;
struct {
u8 action; /* 9 */
u8 oui[3];
/* Vendor-specific content */
u8 variable[0];
} STRUCT_PACKED vs_public_action;
struct {
u8 action; /* 7 */
u8 dialog_token;
u8 req_mode;
le16 disassoc_timer;
u8 validity_interval;
/* BSS Termination Duration (optional),
* Session Information URL (optional),
* BSS Transition Candidate List
* Entries */
u8 variable[0];
} STRUCT_PACKED bss_tm_req;
struct {
u8 action; /* 8 */
u8 dialog_token;
u8 status_code;
u8 bss_termination_delay;
/* Target BSSID (optional),
* BSS Transition Candidate List
* Entries (optional) */
u8 variable[0];
} STRUCT_PACKED bss_tm_resp;
} u;
} STRUCT_PACKED action;
} u;
} STRUCT_PACKED;
/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
#define IEEE80211_HT_MCS_MASK_LEN 10
struct ieee80211_ht_capabilities {
le16 ht_capabilities_info;
u8 a_mpdu_params;
@ -379,6 +575,19 @@ struct ieee80211_ht_operation {
u8 basic_set[16];
} STRUCT_PACKED;
struct ieee80211_vht_capabilities {
le32 vht_capabilities_info;
u8 vht_supported_mcs_set[8];
} STRUCT_PACKED;
struct ieee80211_vht_operation {
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
u8 vht_op_info_chan_center_freq_seg1_idx;
le16 vht_basic_mcs_set;
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@ -460,7 +669,7 @@ struct ieee80211_ht_operation {
#define OP_MODE_MIXED 3
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
((le16) (0x0001 | 0x0002))
(0x0001 | 0x0002)
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
@ -473,11 +682,45 @@ struct ieee80211_ht_operation {
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1))
#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
#define VHT_CAP_RXLDPC ((u32) BIT(4))
#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5))
#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6))
#define VHT_CAP_TXSTBC ((u32) BIT(7))
#define VHT_CAP_RXSTBC_1 ((u32) BIT(8))
#define VHT_CAP_RXSTBC_2 ((u32) BIT(9))
#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9))
#define VHT_CAP_RXSTBC_4 ((u32) BIT(10))
#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11))
#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX ((u32) BIT(13) | BIT(14))
#define VHT_CAP_SOUNDING_DIMENTION_MAX ((u32) BIT(16) | BIT(17))
#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19))
#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20))
#define VHT_CAP_VHT_TXOP_PS ((u32) BIT(21))
#define VHT_CAP_HTC_VHT ((u32) BIT(22))
#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@ -516,6 +759,10 @@ struct wmm_information_element {
} STRUCT_PACKED;
#define WMM_QOSINFO_STA_AC_MASK 0x0f
#define WMM_QOSINFO_STA_SP_MASK 0x03
#define WMM_QOSINFO_STA_SP_SHIFT 5
#define WMM_AC_AIFSN_MASK 0x0f
#define WMM_AC_AIFNS_SHIFT 0
#define WMM_AC_ACM 0x10
@ -544,7 +791,7 @@ struct wmm_parameter_element {
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specif QoS info */
u8 qos_info; /* AP/STA specific QoS info */
u8 reserved; /* 0 */
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
@ -587,6 +834,140 @@ enum {
};
#define HS20_INDICATION_OUI_TYPE 16
#define HS20_ANQP_OUI_TYPE 17
#define HS20_STYPE_QUERY_LIST 1
#define HS20_STYPE_CAPABILITY_LIST 2
#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
#define HS20_STYPE_WAN_METRICS 4
#define HS20_STYPE_CONNECTION_CAPABILITY 5
#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
#define HS20_STYPE_OPERATING_CLASS 7
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
enum p2p_attr_id {
P2P_ATTR_STATUS = 0,
P2P_ATTR_MINOR_REASON_CODE = 1,
P2P_ATTR_CAPABILITY = 2,
P2P_ATTR_DEVICE_ID = 3,
P2P_ATTR_GROUP_OWNER_INTENT = 4,
P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
P2P_ATTR_LISTEN_CHANNEL = 6,
P2P_ATTR_GROUP_BSSID = 7,
P2P_ATTR_EXT_LISTEN_TIMING = 8,
P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
P2P_ATTR_MANAGEABILITY = 10,
P2P_ATTR_CHANNEL_LIST = 11,
P2P_ATTR_NOTICE_OF_ABSENCE = 12,
P2P_ATTR_DEVICE_INFO = 13,
P2P_ATTR_GROUP_INFO = 14,
P2P_ATTR_GROUP_ID = 15,
P2P_ATTR_INTERFACE = 16,
P2P_ATTR_OPERATING_CHANNEL = 17,
P2P_ATTR_INVITATION_FLAGS = 18,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
#define P2P_MAX_GO_INTENT 15
/* P2P Capability - Device Capability bitmap */
#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
/* P2P Capability - Group Capability bitmap */
#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
/* Invitation Flags */
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
/* P2P Manageability */
#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
enum p2p_status_code {
P2P_SC_SUCCESS = 0,
P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
P2P_SC_FAIL_LIMIT_REACHED = 3,
P2P_SC_FAIL_INVALID_PARAMS = 4,
P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
P2P_SC_FAIL_UNKNOWN_GROUP = 8,
P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
};
#define P2P_WILDCARD_SSID "DIRECT-"
#define P2P_WILDCARD_SSID_LEN 7
/* P2P action frames */
enum p2p_act_frame_type {
P2P_NOA = 0,
P2P_PRESENCE_REQ = 1,
P2P_PRESENCE_RESP = 2,
P2P_GO_DISC_REQ = 3
};
/* P2P public action frames */
enum p2p_action_frame_type {
P2P_GO_NEG_REQ = 0,
P2P_GO_NEG_RESP = 1,
P2P_GO_NEG_CONF = 2,
P2P_INVITATION_REQ = 3,
P2P_INVITATION_RESP = 4,
P2P_DEV_DISC_REQ = 5,
P2P_DEV_DISC_RESP = 6,
P2P_PROV_DISC_REQ = 7,
P2P_PROV_DISC_RESP = 8
};
enum p2p_service_protocol_type {
P2P_SERV_ALL_SERVICES = 0,
P2P_SERV_BONJOUR = 1,
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
P2P_SERV_WIFI_DISPLAY = 4,
P2P_SERV_VENDOR_SPECIFIC = 255
};
enum p2p_sd_status {
P2P_SD_SUCCESS = 0,
P2P_SD_PROTO_NOT_AVAILABLE = 1,
P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
P2P_SD_BAD_REQUEST = 3
};
enum wifi_display_subelem {
WFD_SUBELEM_DEVICE_INFO = 0,
WFD_SUBELEM_ASSOCIATED_BSSID = 1,
WFD_SUBELEM_AUDIO_FORMATS = 2,
WFD_SUBELEM_VIDEO_FORMATS = 3,
WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
WFD_SUBELEM_CONTENT_PROTECTION = 5,
WFD_SUBELEM_COUPLED_SINK = 6,
WFD_SUBELEM_EXT_CAPAB = 7,
WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
WFD_SUBELEM_SESSION_INFO = 9
};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@ -599,9 +980,106 @@ enum {
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
#define WLAN_CIPHER_SUITE_SMS4 0x00147201
#define WLAN_CIPHER_SUITE_CKIP 0x00409600
#define WLAN_CIPHER_SUITE_CKIP_CMIC 0x00409601
#define WLAN_CIPHER_SUITE_CMIC 0x00409602
#define WLAN_CIPHER_SUITE_KRK 0x004096FF /* for nl80211 use only */
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
#define WLAN_AKM_SUITE_CCKM 0x00409600
/* IEEE 802.11v - WNM Action field values */
enum wnm_action {
WNM_EVENT_REQ = 0,
WNM_EVENT_REPORT = 1,
WNM_DIAGNOSTIC_REQ = 2,
WNM_DIAGNOSTIC_REPORT = 3,
WNM_LOCATION_CFG_REQ = 4,
WNM_LOCATION_CFG_RESP = 5,
WNM_BSS_TRANS_MGMT_QUERY = 6,
WNM_BSS_TRANS_MGMT_REQ = 7,
WNM_BSS_TRANS_MGMT_RESP = 8,
WNM_FMS_REQ = 9,
WNM_FMS_RESP = 10,
WNM_COLLOCATED_INTERFERENCE_REQ = 11,
WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
WNM_TFS_REQ = 13,
WNM_TFS_RESP = 14,
WNM_TFS_NOTIFY = 15,
WNM_SLEEP_MODE_REQ = 16,
WNM_SLEEP_MODE_RESP = 17,
WNM_TIM_BROADCAST_REQ = 18,
WNM_TIM_BROADCAST_RESP = 19,
WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
WNM_CHANNEL_USAGE_REQ = 21,
WNM_CHANNEL_USAGE_RESP = 22,
WNM_DMS_REQ = 23,
WNM_DMS_RESP = 24,
WNM_TIMING_MEASUREMENT_REQ = 25,
WNM_NOTIFICATION_REQ = 26,
WNM_NOTIFICATION_RESP = 27
};
/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0)
#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1)
#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ BIT(2)
#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ BIT(3)
#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT BIT(4)
struct ieee80211_2040_bss_coex_ie {
u8 element_id;
u8 length;
u8 coex_param;
} STRUCT_PACKED;
struct ieee80211_2040_intol_chan_report {
u8 element_id;
u8 length;
u8 op_class;
u8 variable[0]; /* Channel List */
} STRUCT_PACKED;
/* IEEE 802.11v - WNM-Sleep Mode element */
struct wnm_sleep_element {
u8 eid; /* WLAN_EID_WNMSLEEP */
u8 len;
u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */
u8 status;
le16 intval;
} STRUCT_PACKED;
#define WNM_SLEEP_MODE_ENTER 0
#define WNM_SLEEP_MODE_EXIT 1
enum wnm_sleep_mode_response_status {
WNM_STATUS_SLEEP_ACCEPT = 0,
WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
WNM_STATUS_DENIED_ACTION = 2,
WNM_STATUS_DENIED_TMP = 3,
WNM_STATUS_DENIED_KEY = 4,
WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
};
/* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
WNM_SLEEP_SUBELEM_IGTK = 1
};
#endif /* IEEE802_11_DEFS_H */

View File

@ -2,14 +2,8 @@
* WPA Supplicant - privilege separation commands
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef PRIVSEP_COMMANDS_H

View File

@ -1,6 +1,10 @@
#ifndef VERSION_H
#define VERSION_H
#define VERSION_STR "0.7.3"
#ifndef VERSION_STR_POSTFIX
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
#define VERSION_STR "2.0" VERSION_STR_POSTFIX
#endif /* VERSION_H */

Some files were not shown because too many files have changed in this diff Show More