import wpa_supplicant+hostapd 0.6.8

This commit is contained in:
sam 2009-03-01 22:10:07 +00:00
commit c164510d5a
566 changed files with 235174 additions and 0 deletions

340
COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
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.

19
README Normal file
View File

@ -0,0 +1,19 @@
wpa_supplicant and hostapd v0.6.x
---------------------------------
Copyright (c) 2002-2007, 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.
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).

7
hostapd/.gitignore vendored Normal file
View File

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

565
hostapd/ChangeLog Normal file
View File

@ -0,0 +1,565 @@
ChangeLog for hostapd
2009-02-15 - v0.6.8
* increased hostapd_cli ping interval to 5 seconds and made this
configurable with a new command line options (-G<seconds>)
* driver_nl80211: use Linux socket filter to improve performance
* added support for external Registrars with WPS (UPnP transport)
2009-01-06 - v0.6.7
* added support for Wi-Fi Protected Setup (WPS)
(hostapd can now be configured to act as an integrated WPS Registrar
and provision credentials for WPS Enrollees using PIN and PBC
methods; external wireless Registrar can configure the AP, but
external WLAN Manager Registrars are not supported); WPS support can
be enabled by adding CONFIG_WPS=y into .config and setting the
runtime configuration variables in hostapd.conf (see WPS section in
the example configuration file); new hostapd_cli commands wps_pin and
wps_pbc are used to configure WPS negotiation; see README-WPS for
more details
* added IEEE 802.11n HT capability configuration (ht_capab)
* added support for generating Country IE based on nl80211 regulatory
information (added if ieee80211d=1 in configuration)
* fixed WEP authentication (both Open System and Shared Key) with
mac80211
* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
* added support for using driver_test over UDP socket
* changed EAP-GPSK to use the IANA assigned EAP method type 51
* updated management frame protection to use IEEE 802.11w/D7.0
* fixed retransmission of EAP requests if no response is received
2008-11-23 - v0.6.6
* added a new configuration option, wpa_ptk_rekey, that can be used to
enforce frequent PTK rekeying, e.g., to mitigate some attacks against
TKIP deficiencies
* updated OpenSSL code for EAP-FAST to use an updated version of the
session ticket overriding API that was included into the upstream
OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
needed with that version anymore)
* changed channel flags configuration to read the information from
the driver (e.g., via driver_nl80211 when using mac80211) instead of
using hostapd as the source of the regulatory information (i.e.,
information from CRDA is now used with mac80211); this allows 5 GHz
channels to be used with hostapd (if allowed in the current
regulatory domain)
* fixed EAP-TLS message processing for the last TLS message if it is
large enough to require fragmentation (e.g., if a large Session
Ticket data is included)
* fixed listen interval configuration for nl80211 drivers
2008-11-01 - v0.6.5
* added support for SHA-256 as X.509 certificate digest when using the
internal X.509/TLSv1 implementation
* fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
identity lengths)
* fixed internal TLSv1 implementation for abbreviated handshake (used
by EAP-FAST server)
* added support for setting VLAN ID for STAs based on local MAC ACL
(accept_mac_file) as an alternative for RADIUS server-based
configuration
* updated management frame protection to use IEEE 802.11w/D6.0
(adds a new association ping to protect against unauthenticated
authenticate or (re)associate request frames dropping association)
* added support for using SHA256-based stronger key derivation for WPA2
(IEEE 802.11w)
* added new "driver wrapper" for RADIUS-only configuration
(driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
* fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
is enabled in configuration
* changed EAP-FAST configuration to use separate fields for A-ID and
A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
16-octet len binary value for better interoperability with some peer
implementations; eap_fast_a_id is now configured as a hex string
* driver_nl80211: Updated to match the current Linux mac80211 AP mode
configuration (wireless-testing.git and Linux kernel releases
starting from 2.6.29)
2008-08-10 - v0.6.4
* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
Identity Request if identity is already known
* added support for EAP Sequences in EAP-FAST Phase 2
* added support for EAP-TNC (Trusted Network Connect)
(this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
changes needed to run two methods in sequence (IF-T) and the IF-IMV
and IF-TNCCS interfaces from TNCS)
* added support for optional cryptobinding with PEAPv0
* added fragmentation support for EAP-TNC
* added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
data
* added support for opportunistic key caching (OKC)
2008-02-22 - v0.6.3
* fixed Reassociation Response callback processing when using internal
MLME (driver_{hostap,nl80211,test}.c)
* updated FT support to use the latest draft, IEEE 802.11r/D9.0
* copy optional Proxy-State attributes into RADIUS response when acting
as a RADIUS authentication server
* fixed EAPOL state machine to handle a case in which no response is
received from the RADIUS authentication server; previous version
could have triggered a crash in some cases after a timeout
* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
be used
* added a workaround for EAP-SIM/AKA peers that include incorrect null
termination in the username
* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
attribute in notification messages only when using fast
reauthentication
* fixed EAP-SIM Start response processing for fast reauthentication
case
* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
2008-01-01 - v0.6.2
* fixed EAP-SIM and EAP-AKA message parser to validate attribute
lengths properly to avoid potential crash caused by invalid messages
* added data structure for storing allocated buffers (struct wpabuf);
this does not affect hostapd usage, but many of the APIs changed
and various interfaces (e.g., EAP) is not compatible with old
versions
* added support for protecting EAP-AKA/Identity messages with
AT_CHECKCODE (optional feature in RFC 4187)
* added support for protected result indication with AT_RESULT_IND for
EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
* added support for configuring EAP-TTLS phase 2 non-EAP methods in
EAP server configuration; previously all four were enabled for every
phase 2 user, now all four are disabled by default and need to be
enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
TTLS-MSCHAPV2
* removed old debug printing mechanism and the related 'debug'
parameter in the configuration file; debug verbosity is now set with
-d (or -dd) command line arguments
* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
only shared key/password authentication is supported in this version
2007-11-24 - v0.6.1
* added experimental, integrated TLSv1 server implementation with the
needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
.config); this can be useful, e.g., if the target system does not
have a suitable TLS library and a minimal code size is required
* added support for EAP-FAST server method to the integrated EAP
server
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
draft (draft-ietf-emu-eap-gpsk-07.txt)
* added a new configuration parameter, rsn_pairwise, to allow different
pairwise cipher suites to be enabled for WPA and RSN/WPA2
(note: if wpa_pairwise differs from rsn_pairwise, the driver will
either need to support this or will have to use the WPA/RSN IEs from
hostapd; currently, the included madwifi and bsd driver interfaces do
not have support for this)
* updated FT support to use the latest draft, IEEE 802.11r/D8.0
2007-05-28 - v0.6.0
* added experimental IEEE 802.11r/D6.0 support
* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
* updated EAP-PSK to use the IANA-allocated EAP type 47
* fixed EAP-PSK bit ordering of the Flags field
* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
by reading wpa_psk_file [Bug 181]
* fixed EAP-TTLS AVP parser processing for too short AVP lengths
* fixed IPv6 connection to RADIUS accounting server
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
draft (draft-ietf-emu-eap-gpsk-04.txt)
* hlr_auc_gw: read GSM triplet file into memory and rotate through the
entries instead of only using the same three triplets every time
(this does not work properly with tests using multiple clients, but
provides bit better triplet data for testing a single client; anyway,
if a better quality triplets are needed, GSM-Milenage should be used
instead of hardcoded triplet file)
* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
in Success Request [Bug 203]
* added support for sending EAP-AKA Notifications in error cases
* updated to use IEEE 802.11w/D2.0 for management frame protection
(still experimental)
* RADIUS server: added support for processing duplicate messages
(retransmissions from RADIUS client) by replying with the previous
reply
2006-11-24 - v0.5.6
* added support for configuring and controlling multiple BSSes per
radio interface (bss=<ifname> in hostapd.conf); this is only
available with Devicescape and test driver interfaces
* fixed PMKSA cache update in the end of successful RSN
pre-authentication
* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
for each STA based on RADIUS Access-Accept attributes); this requires
VLAN support from the kernel driver/802.11 stack and this is
currently only available with Devicescape and test driver interfaces
* driver_madwifi: fixed configuration of unencrypted modes (plaintext
and IEEE 802.1X without WEP)
* removed STAKey handshake since PeerKey handshake has replaced it in
IEEE 802.11ma and there are no known deployments of STAKey
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
draft (draft-ietf-emu-eap-gpsk-01.txt)
* added preliminary implementation of IEEE 802.11w/D1.0 (management
frame protection)
(Note: this requires driver support to work properly.)
(Note2: IEEE 802.11w is an unapproved draft and subject to change.)
* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
parameters from a text file to make it possible to implement proper
GSM/UMTS authentication server for multiple SIM/USIM cards using
EAP-SIM/EAP-AKA
* fixed session timeout processing with drivers that do not use
ieee802_11.c (e.g., madwifi)
2006-08-27 - v0.5.5
* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
hostapd (e.g., to initialize wired network authentication based on an
external signal)
* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
using WPA2 even if PMKSA caching is not used
* added -P<pid file> argument for hostapd to write the current process
id into a file
* added support for RADIUS Authentication Server MIB (RFC 2619)
2006-06-20 - v0.5.4
* fixed nt_password_hash build [Bug 144]
* added PeerKey handshake implementation for IEEE 802.11e
direct link setup (DLS) to replace STAKey handshake
* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
draft-clancy-emu-eap-shared-secret-00.txt)
* fixed a segmentation fault when RSN pre-authentication was completed
successfully [Bug 152]
2006-04-27 - v0.5.3
* do not build nt_password_hash and hlr_auc_gw by default to avoid
requiring a TLS library for a successful build; these programs can be
build with 'make nt_password_hash' and 'make hlr_auc_gw'
* added a new configuration option, eapol_version, that can be used to
set EAPOL version to 1 (default is 2) to work around broken client
implementations that drop EAPOL frames which use version number 2
[Bug 89]
* added support for EAP-SAKE (no EAP method number allocated yet, so
this is using the same experimental type 255 as EAP-PSK)
* fixed EAP-MSCHAPv2 message length validation
2006-03-19 - v0.5.2
* fixed stdarg use in hostapd_logger(): if both stdout and syslog
logging was enabled, hostapd could trigger a segmentation fault in
vsyslog on some CPU -- C library combinations
* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
program to make it easier to use for implementing real SS7 gateway;
eap_sim_db is not anymore used as a file name for GSM authentication
triplets; instead, it is path to UNIX domain socket that will be used
to communicate with the external gateway program (e.g., hlr_auc_gw)
* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
local information (GSM authentication triplets from a text file and
hardcoded AKA authentication data); this can be used to test EAP-SIM
and EAP-AKA
* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
to make it possible to test EAP-AKA with real USIM cards (this is
disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
to enable this)
* driver_madwifi: added support for getting station RSN IE from
madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
broken with earlier change (r1357) in the driver
* changed EAP method registration to use a dynamic list of methods
instead of a static list generated at build time
* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
[Bug 125]
* added ap_max_inactivity configuration parameter
2006-01-29 - v0.5.1
* driver_test: added better support for multiple APs and STAs by using
a directory with sockets that include MAC address for each device in
the name (test_socket=DIR:/tmp/test)
* added support for EAP expanded type (vendor specific EAP methods)
2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
* added experimental STAKey handshake implementation for IEEE 802.11e
direct link setup (DLS); note: this is disabled by default in both
build and runtime configuration (can be enabled with CONFIG_STAKEY=y
and stakey=1)
* added support for EAP methods to use callbacks to external programs
by buffering a pending request and processing it after the EAP method
is ready to continue
* improved EAP-SIM database interface to allow external request to GSM
HLR/AuC without blocking hostapd process
* added support for using EAP-SIM pseudonyms and fast re-authentication
* added support for EAP-AKA in the integrated EAP authenticator
* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
user database to allow EAP-SIM/AKA selection without extra roundtrip
for EAP-Nak negotiation
* added support for storing EAP user password as NtPasswordHash instead
of plaintext password when using MSCHAP or MSCHAPv2 for
authentication (hash:<16-octet hex value>); added nt_password_hash
tool for hashing password to generate NtPasswordHash
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
* driver_wired: fixed EAPOL sending to optionally use PAE group address
as the destination instead of supplicant MAC address; this is
disabled by default, but should be enabled with use_pae_group_addr=1
in configuration file if the wired interface is used by only one
device at the time (common switch configuration)
* driver_madwifi: configure driver to use TKIP countermeasures in order
to get correct behavior (IEEE 802.11 association failing; previously,
association succeeded, but hostpad forced disassociation immediately)
* driver_madwifi: added support for madwifi-ng
2005-10-27 - v0.4.6
* added support for replacing user identity from EAP with RADIUS
User-Name attribute from Access-Accept message, if that is included,
for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
tunneled identity into accounting messages when the RADIUS server
does not support better way of doing this with Class attribute)
* driver_madwifi: fixed EAPOL packet receive for configuration where
ath# is part of a bridge interface
* added a configuration file and log analyzer script for logwatch
* fixed EAPOL state machine step function to process all state
transitions before processing new events; this resolves a race
condition in which EAPOL-Start message could trigger hostapd to send
two EAP-Response/Identity frames to the authentication server
2005-09-25 - v0.4.5
* added client CA list to the TLS certificate request in order to make
it easier for the client to select which certificate to use
* added experimental support for EAP-PSK
* added support for WE-19 (hostap, madwifi)
2005-08-21 - v0.4.4
* fixed build without CONFIG_RSN_PREAUTH
* fixed FreeBSD build
2005-06-26 - v0.4.3
* fixed PMKSA caching to copy User-Name and Class attributes so that
RADIUS accounting gets correct information
* start RADIUS accounting only after successful completion of WPA
4-Way Handshake if WPA-PSK is used
* fixed PMKSA caching for the case where STA (re)associates without
first disassociating
2005-06-12 - v0.4.2
* EAP-PAX is now registered as EAP type 46
* fixed EAP-PAX MAC calculation
* fixed EAP-PAX CK and ICK key derivation
* renamed eap_authenticator configuration variable to eap_server to
better match with RFC 3748 (EAP) terminology
* driver_test: added support for testing hostapd with wpa_supplicant
by using test driver interface without any kernel drivers or network
cards
2005-05-22 - v0.4.1
* fixed RADIUS server initialization when only auth or acct server
is configured and the other one is left empty
* driver_madwifi: added support for RADIUS accounting
* driver_madwifi: added preliminary support for compiling against 'BSD'
branch of madwifi CVS tree
* driver_madwifi: fixed pairwise key removal to allow WPA reauth
without disassociation
* added support for reading additional certificates from PKCS#12 files
and adding them to the certificate chain
* fixed RADIUS Class attribute processing to only use Access-Accept
packets to update Class; previously, other RADIUS authentication
packets could have cleared Class attribute
* added support for more than one Class attribute in RADIUS packets
* added support for verifying certificate revocation list (CRL) when
using integrated EAP authenticator for EAP-TLS; new hostapd.conf
options 'check_crl'; CRL must be included in the ca_cert file for now
2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
* added support for including network information into
EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
(e.g., to implement draft-adrange-eap-network-discovery-07.txt)
* fixed a bug which caused some RSN pre-authentication cases to use
freed memory and potentially crash hostapd
* fixed private key loading for cases where passphrase is not set
* added support for sending TLS alerts and aborting authentication
when receiving a TLS alert
* fixed WPA2 to add PMKSA cache entry when using integrated EAP
authenticator
* fixed PMKSA caching (EAP authentication was not skipped correctly
with the new state machine changes from IEEE 802.1X draft)
* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
to be added to .config to include IPv6 support); for RADIUS server,
radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
in RADIUS clients file can then use IPv6 format
* added experimental support for EAP-PAX
* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
2005-01-23 - v0.3.5
* added support for configuring a forced PEAP version based on the
Phase 1 identity
* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
to terminate authentication
* fixed EAP identifier duplicate processing with the new IEEE 802.1X
draft
* clear accounting data in the driver when starting a new accounting
session
* driver_madwifi: filter wireless events based on ifindex to allow more
than one network interface to be used
* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
setting if the packet does not pass MIC verification (e.g., due to
incorrect PSK); previously, message 1/4 was not tried again if an
invalid message 2/4 was received
* fixed reconfiguration of RADIUS client retransmission timer when
adding a new message to the pending list; previously, timer was not
updated at this point and if there was a pending message with long
time for the next retry, the new message needed to wait that long for
its first retry, too
2005-01-09 - v0.3.4
* added support for configuring multiple allowed EAP types for Phase 2
authentication (EAP-PEAP, EAP-TTLS)
* fixed EAPOL-Start processing to trigger WPA reauthentication
(previously, only EAPOL authentication was done)
2005-01-02 - v0.3.3
* added support for EAP-PEAP in the integrated EAP authenticator
* added support for EAP-GTC in the integrated EAP authenticator
* added support for configuring list of EAP methods for Phase 1 so that
the integrated EAP authenticator can, e.g., use the wildcard entry
for EAP-TLS and EAP-PEAP
* added support for EAP-TTLS in the integrated EAP authenticator
* added support for EAP-SIM in the integrated EAP authenticator
* added support for using hostapd as a RADIUS authentication server
with the integrated EAP authenticator taking care of EAP
authentication (new hostapd.conf options: radius_server_clients and
radius_server_auth_port); this is not included in default build; use
CONFIG_RADIUS_SERVER=y in .config to include
2004-12-19 - v0.3.2
* removed 'daemonize' configuration file option since it has not really
been used at all for more than year
* driver_madwifi: fixed group key setup and added get_ssid method
* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
2004-12-12 - v0.3.1
* added support for integrated EAP-TLS authentication (new hostapd.conf
variables: ca_cert, server_cert, private_key, private_key_passwd);
this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
external RADIUS server
* added support for reading PKCS#12 (PFX) files (as a replacement for
PEM/DER) to get certificate and private key (CONFIG_PKCS12)
2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
* added support for Acct-{Input,Output}-Gigawords
* added support for Event-Timestamp (in RADIUS Accounting-Requests)
* added support for RADIUS Authentication Client MIB (RFC2618)
* added support for RADIUS Accounting Client MIB (RFC2620)
* made EAP re-authentication period configurable (eap_reauth_period)
* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
* fixed EAPOL state machine to stop if STA is removed during
eapol_sm_step(); this fixes at least one segfault triggering bug with
IEEE 802.11i pre-authentication
* added support for multiple WPA pre-shared keys (e.g., one for each
client MAC address or keys shared by a group of clients);
new hostapd.conf field wpa_psk_file for setting path to a text file
containing PSKs, see hostapd.wpa_psk for an example
* added support for multiple driver interfaces to allow hostapd to be
used with other drivers
* added wired authenticator driver interface (driver=wired in
hostapd.conf, see wired.conf for example configuration)
* added madwifi driver interface (driver=madwifi in hostapd.conf, see
madwifi.conf for example configuration; Note: include files from
madwifi project is needed for building and a configuration file,
.config, needs to be created in hostapd directory with
CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
build)
* fixed an alignment issue that could cause SHA-1 to fail on some
platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
align variables)
* fixed RADIUS reconnection after an error in sending interim
accounting packets
* added hostapd control interface for external programs and an example
CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
'hostapd_cli sta <addr>')
* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
* added support for strict GTK rekeying (wpa_strict_rekey in
hostapd.conf)
* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
(instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
IEEE 802.11F-2003)
* added Prism54 driver interface (driver=prism54 in hostapd.conf;
note: .config needs to be created in hostapd directory with
CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
build)
* dual-licensed hostapd (GPLv2 and BSD licenses)
* fixed RADIUS accounting to generate a new session id for cases where
a station reassociates without first being complete deauthenticated
* fixed STA disassociation handler to mark next timeout state to
deauthenticate the station, i.e., skip long wait for inactivity poll
and extra disassociation, if the STA disassociates without
deauthenticating
* added integrated EAP authenticator that can be used instead of
external RADIUS authentication server; currently, only EAP-MD5 is
supported, so this cannot yet be used for key distribution; the EAP
method interface is generic, though, so adding new EAP methods should
be straightforward; new hostapd.conf variables: 'eap_authenticator'
and 'eap_user_file'; this obsoletes "minimal authentication server"
('minimal_eap' in hostapd.conf) which is now removed
* added support for FreeBSD and driver interface for the BSD net80211
layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
.config); please note that some of the required kernel mods have not
yet been committed
2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
* fixed some accounting cases where Accounting-Start was sent when
IEEE 802.1X port was being deauthorized
2004-06-20 - v0.2.3
* modified RADIUS client to re-connect the socket in case of certain
error codes that are generated when a network interface state is
changes (e.g., when IP address changes or the interface is set UP)
* fixed couple of cases where EAPOL state for a station was freed
twice causing a segfault for hostapd
* fixed couple of bugs in processing WPA deauthentication (freed data
was used)
2004-05-31 - v0.2.2
* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
cases where STAs dropped multicast frames as replay attacks
* added support for copying RADIUS Attribute 'Class' from
authentication messages into accounting messages
* send canned EAP failure if RADIUS server sends Access-Reject without
EAP message (previously, Supplicant was not notified in this case)
* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
not start EAPOL state machines if the STA selected to use WPA-PSK)
2004-05-06 - v0.2.1
* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
- based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
(i.e., IEEE 802.11i/D3.0)
- supports WPA-only, RSN-only, and mixed WPA/RSN mode
- both WPA-PSK and WPA-RADIUS/EAP are supported
- PMKSA caching and pre-authentication
- new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
rsn_preauth, rsn_preauth_interfaces
* fixed interim accounting to remove any pending accounting messages
to the STA before sending a new one
2004-02-15 - v0.2.0
* added support for Acct-Interim-Interval:
- draft-ietf-radius-acct-interim-01.txt
- use Acct-Interim-Interval attribute from Access-Accept if local
'radius_acct_interim_interval' is not set
- allow different update intervals for each STA
* fixed event loop to call signal handlers only after returning from
the real signal handler
* reset sta->timeout_next after successful association to make sure
that the previously registered inactivity timer will not remove the
STA immediately (e.g., if STA deauthenticates and re-associates
before the timer is triggered).
* added new hostapd.conf variable, nas_identifier, that can be used to
add an optional RADIUS Attribute, NAS-Identifier, into authentication
and accounting messages
* added support for Accounting-On and Accounting-Off messages
* fixed accounting session handling to send Accounting-Start only once
per session and not to send Accounting-Stop if the session was not
initialized properly
* fixed Accounting-Stop statistics in cases where the message was
previously sent after the kernel entry for the STA (and/or IEEE
802.1X data) was removed
Note:
Older changes up to and including v0.1.0 are included in the ChangeLog
of the Host AP driver.

602
hostapd/Makefile Normal file
View File

@ -0,0 +1,602 @@
ifndef CC
CC=gcc
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
# a file (undefine it, if you want to save in binary size)
CFLAGS += -DHOSTAPD_DUMP_STATE
CFLAGS += -I../src
CFLAGS += -I../src/crypto
CFLAGS += -I../src/utils
CFLAGS += -I../src/common
# Uncomment following line and set the path to your kernel tree include
# directory if your C library does not include all header files.
# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
-include .config
ifndef CONFIG_OS
ifdef CONFIG_NATIVE_WINDOWS
CONFIG_OS=win32
else
CONFIG_OS=unix
endif
endif
ifeq ($(CONFIG_OS), internal)
CFLAGS += -DOS_NO_C_LIB_DEFINES
endif
ifdef CONFIG_NATIVE_WINDOWS
CFLAGS += -DCONFIG_NATIVE_WINDOWS
LIBS += -lws2_32
endif
OBJS = hostapd.o ieee802_1x.o eapol_sm.o \
ieee802_11.o config.o ieee802_11_auth.o accounting.o \
sta_info.o wpa.o ctrl_iface.o \
drivers.o preauth.o pmksa_cache.o beacon.o \
hw_features.o wme.o ap_list.o \
mlme.o vlan_init.o wpa_auth_ie.o
OBJS += ../src/utils/eloop.o
OBJS += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/os_$(CONFIG_OS).o
OBJS += ../src/utils/ip_addr.o
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
OBJS += ../src/radius/radius.o
OBJS += ../src/radius/radius_client.o
OBJS += ../src/crypto/md5.o
OBJS += ../src/crypto/rc4.o
OBJS += ../src/crypto/md4.o
OBJS += ../src/crypto/sha1.o
OBJS += ../src/crypto/des.o
OBJS += ../src/crypto/aes_wrap.o
OBJS += ../src/crypto/aes.o
HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
ifdef CONFIG_IAPP
CFLAGS += -DCONFIG_IAPP
OBJS += iapp.o
endif
ifdef CONFIG_RSN_PREAUTH
CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_PEERKEY
CFLAGS += -DCONFIG_PEERKEY
OBJS += peerkey.o
endif
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
endif
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += wpa_ft.o
NEED_SHA256=y
endif
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_DRIVER_HOSTAP
CFLAGS += -DCONFIG_DRIVER_HOSTAP
OBJS += driver_hostap.o
endif
ifdef CONFIG_DRIVER_WIRED
CFLAGS += -DCONFIG_DRIVER_WIRED
OBJS += driver_wired.o
endif
ifdef CONFIG_DRIVER_MADWIFI
CFLAGS += -DCONFIG_DRIVER_MADWIFI
OBJS += driver_madwifi.o
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_DRIVER_PRISM54
CFLAGS += -DCONFIG_DRIVER_PRISM54
OBJS += driver_prism54.o
endif
ifdef CONFIG_DRIVER_NL80211
CFLAGS += -DCONFIG_DRIVER_NL80211
OBJS += driver_nl80211.o radiotap.o
LIBS += -lnl
ifdef CONFIG_LIBNL20
LIBS += -lnl-genl
CFLAGS += -DCONFIG_LIBNL20
endif
endif
ifdef CONFIG_DRIVER_BSD
CFLAGS += -DCONFIG_DRIVER_BSD
OBJS += driver_bsd.o
CONFIG_L2_PACKET=y
CONFIG_DNET_PCAP=y
CONFIG_L2_FREEBSD=y
endif
ifdef CONFIG_DRIVER_TEST
CFLAGS += -DCONFIG_DRIVER_TEST
OBJS += driver_test.o
endif
ifdef CONFIG_DRIVER_NONE
CFLAGS += -DCONFIG_DRIVER_NONE
OBJS += driver_none.o
endif
ifdef CONFIG_L2_PACKET
ifdef CONFIG_DNET_PCAP
ifdef CONFIG_L2_FREEBSD
LIBS += -lpcap
OBJS += ../src/l2_packet/l2_packet_freebsd.o
else
LIBS += -ldnet -lpcap
OBJS += ../src/l2_packet/l2_packet_pcap.o
endif
else
OBJS += ../src/l2_packet/l2_packet_linux.o
endif
else
OBJS += ../src/l2_packet/l2_packet_none.o
endif
ifdef CONFIG_EAP_MD5
CFLAGS += -DEAP_MD5
OBJS += ../src/eap_server/eap_md5.o
CHAP=y
endif
ifdef CONFIG_EAP_TLS
CFLAGS += -DEAP_TLS
OBJS += ../src/eap_server/eap_tls.o
TLS_FUNCS=y
endif
ifdef CONFIG_EAP_PEAP
CFLAGS += -DEAP_PEAP
OBJS += ../src/eap_server/eap_peap.o
OBJS += ../src/eap_common/eap_peap_common.o
TLS_FUNCS=y
CONFIG_EAP_MSCHAPV2=y
endif
ifdef CONFIG_EAP_TTLS
CFLAGS += -DEAP_TTLS
OBJS += ../src/eap_server/eap_ttls.o
TLS_FUNCS=y
CHAP=y
endif
ifdef CONFIG_EAP_MSCHAPV2
CFLAGS += -DEAP_MSCHAPv2
OBJS += ../src/eap_server/eap_mschapv2.o
MS_FUNCS=y
endif
ifdef CONFIG_EAP_GTC
CFLAGS += -DEAP_GTC
OBJS += ../src/eap_server/eap_gtc.o
endif
ifdef CONFIG_EAP_SIM
CFLAGS += -DEAP_SIM
OBJS += ../src/eap_server/eap_sim.o
CONFIG_EAP_SIM_COMMON=y
endif
ifdef CONFIG_EAP_AKA
CFLAGS += -DEAP_AKA
OBJS += ../src/eap_server/eap_aka.o
CONFIG_EAP_SIM_COMMON=y
endif
ifdef CONFIG_EAP_AKA_PRIME
CFLAGS += -DEAP_AKA_PRIME
endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
# replaced with another file implementating the interface specified in
# eap_sim_db.h.
OBJS += ../src/eap_server/eap_sim_db.o
NEED_FIPS186_2_PRF=y
endif
ifdef CONFIG_EAP_PAX
CFLAGS += -DEAP_PAX
OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o
endif
ifdef CONFIG_EAP_PSK
CFLAGS += -DEAP_PSK
OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o
endif
ifdef CONFIG_EAP_SAKE
CFLAGS += -DEAP_SAKE
OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o
endif
ifdef CONFIG_EAP_GPSK
CFLAGS += -DEAP_GPSK
OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
ifdef CONFIG_EAP_GPSK_SHA256
CFLAGS += -DEAP_GPSK_SHA256
endif
NEED_SHA256=y
endif
ifdef CONFIG_EAP_VENDOR_TEST
CFLAGS += -DEAP_VENDOR_TEST
OBJS += ../src/eap_server/eap_vendor_test.o
endif
ifdef CONFIG_EAP_FAST
CFLAGS += -DEAP_FAST
OBJS += ../src/eap_server/eap_fast.o
OBJS += ../src/eap_common/eap_fast_common.o
TLS_FUNCS=y
NEED_T_PRF=y
endif
ifdef CONFIG_WPS
CFLAGS += -DCONFIG_WPS -DEAP_WSC
OBJS += ../src/utils/uuid.o
OBJS += wps_hostapd.o
OBJS += ../src/eap_server/eap_wsc.o ../src/eap_common/eap_wsc_common.o
OBJS += ../src/wps/wps.o
OBJS += ../src/wps/wps_common.o
OBJS += ../src/wps/wps_attr_parse.o
OBJS += ../src/wps/wps_attr_build.o
OBJS += ../src/wps/wps_attr_process.o
OBJS += ../src/wps/wps_dev_attr.o
OBJS += ../src/wps/wps_enrollee.o
OBJS += ../src/wps/wps_registrar.o
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_CRYPTO=y
NEED_BASE64=y
ifdef CONFIG_WPS_UPNP
CFLAGS += -DCONFIG_WPS_UPNP
OBJS += ../src/wps/wps_upnp.o
OBJS += ../src/wps/wps_upnp_ssdp.o
OBJS += ../src/wps/wps_upnp_web.o
OBJS += ../src/wps/wps_upnp_event.o
OBJS += ../src/wps/httpread.o
endif
endif
ifdef CONFIG_EAP_IKEV2
CFLAGS += -DEAP_IKEV2
OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o
OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
NEED_DH_GROUPS=y
endif
ifdef CONFIG_EAP_TNC
CFLAGS += -DEAP_TNC
OBJS += ../src/eap_server/eap_tnc.o
OBJS += ../src/eap_server/tncs.o
NEED_BASE64=y
LIBS += -ldl
endif
# Basic EAP functionality is needed for EAPOL
OBJS += ../src/eap_server/eap.o
OBJS += ../src/eap_common/eap_common.o
OBJS += ../src/eap_server/eap_methods.o
OBJS += ../src/eap_server/eap_identity.o
ifdef CONFIG_EAP
CFLAGS += -DEAP_SERVER
endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
endif
endif
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
CFLAGS += -DCONFIG_INTERNAL_X509
endif
ifeq ($(CONFIG_CRYPTO), internal)
CFLAGS += -DCONFIG_INTERNAL_X509
endif
ifdef TLS_FUNCS
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
CFLAGS += -DEAP_TLS_FUNCS
OBJS += ../src/eap_server/eap_tls_common.o
NEED_TLS_PRF=y
ifeq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/tls_openssl.o
LIBS += -lssl -lcrypto
LIBS_p += -lcrypto
LIBS_h += -lcrypto
endif
ifeq ($(CONFIG_TLS), gnutls)
OBJS += ../src/crypto/tls_gnutls.o
LIBS += -lgnutls -lgcrypt -lgpg-error
LIBS_p += -lgcrypt
LIBS_h += -lgcrypt
endif
ifdef CONFIG_GNUTLS_EXTRA
CFLAGS += -DCONFIG_GNUTLS_EXTRA
LIBS += -lgnutls-extra
endif
ifeq ($(CONFIG_TLS), internal)
OBJS += ../src/crypto/tls_internal.o
OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o
OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
OBJS_p += ../src/tls/asn1.o
OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
NEED_BASE64=y
CFLAGS += -DCONFIG_TLS_INTERNAL
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
ifeq ($(CONFIG_CRYPTO), internal)
ifdef CONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
else
LIBS += -ltommath
LIBS_p += -ltommath
endif
endif
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
LIBS += -ltomcrypt -ltfm
LIBS_p += -ltomcrypt -ltfm
endif
endif
NEED_CRYPTO=y
else
OBJS += ../src/crypto/tls_none.o
endif
ifdef CONFIG_PKCS12
CFLAGS += -DPKCS12_FUNCS
endif
ifdef MS_FUNCS
OBJS += ../src/crypto/ms_funcs.o
NEED_CRYPTO=y
endif
ifdef CHAP
OBJS += ../src/eap_common/chap.o
endif
ifdef NEED_CRYPTO
ifndef TLS_FUNCS
ifeq ($(CONFIG_TLS), openssl)
LIBS += -lcrypto
LIBS_p += -lcrypto
LIBS_h += -lcrypto
endif
ifeq ($(CONFIG_TLS), gnutls)
LIBS += -lgcrypt
LIBS_p += -lgcrypt
LIBS_h += -lgcrypt
endif
ifeq ($(CONFIG_TLS), internal)
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
LIBS += -ltomcrypt -ltfm
LIBS_p += -ltomcrypt -ltfm
endif
endif
endif
ifeq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/crypto_openssl.o
OBJS_p += ../src/crypto/crypto_openssl.o
HOBJS += ../src/crypto/crypto_openssl.o
CONFIG_INTERNAL_SHA256=y
endif
ifeq ($(CONFIG_TLS), gnutls)
OBJS += ../src/crypto/crypto_gnutls.o
OBJS_p += ../src/crypto/crypto_gnutls.o
HOBJS += ../src/crypto/crypto_gnutls.o
CONFIG_INTERNAL_SHA256=y
endif
ifeq ($(CONFIG_TLS), internal)
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
OBJS += ../src/crypto/crypto_libtomcrypt.o
OBJS_p += ../src/crypto/crypto_libtomcrypt.o
CONFIG_INTERNAL_SHA256=y
endif
ifeq ($(CONFIG_CRYPTO), internal)
OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
CONFIG_INTERNAL_AES=y
CONFIG_INTERNAL_DES=y
CONFIG_INTERNAL_SHA1=y
CONFIG_INTERNAL_MD4=y
CONFIG_INTERNAL_MD5=y
CONFIG_INTERNAL_SHA256=y
endif
endif
else
CONFIG_INTERNAL_AES=y
CONFIG_INTERNAL_SHA1=y
CONFIG_INTERNAL_MD5=y
CONFIG_INTERNAL_SHA256=y
endif
ifdef CONFIG_INTERNAL_AES
CFLAGS += -DINTERNAL_AES
endif
ifdef CONFIG_INTERNAL_SHA1
CFLAGS += -DINTERNAL_SHA1
endif
ifdef CONFIG_INTERNAL_SHA256
CFLAGS += -DINTERNAL_SHA256
endif
ifdef CONFIG_INTERNAL_MD5
CFLAGS += -DINTERNAL_MD5
endif
ifdef CONFIG_INTERNAL_MD4
CFLAGS += -DINTERNAL_MD4
endif
ifdef CONFIG_INTERNAL_DES
CFLAGS += -DINTERNAL_DES
endif
ifdef NEED_SHA256
OBJS += ../src/crypto/sha256.o
endif
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
endif
ifndef NEED_FIPS186_2_PRF
CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
endif
ifndef NEED_T_PRF
CFLAGS += -DCONFIG_NO_T_PRF
endif
ifndef NEED_TLS_PRF
CFLAGS += -DCONFIG_NO_TLS_PRF
endif
ifdef CONFIG_RADIUS_SERVER
CFLAGS += -DRADIUS_SERVER
OBJS += ../src/radius/radius_server.o
endif
ifdef CONFIG_IPV6
CFLAGS += -DCONFIG_IPV6
endif
ifdef CONFIG_DRIVER_RADIUS_ACL
CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
endif
ifdef CONFIG_FULL_DYNAMIC_VLAN
# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
# and vlan interfaces for the vlan feature.
CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
endif
ifdef NEED_BASE64
OBJS += ../src/utils/base64.o
endif
ifdef CONFIG_NO_STDOUT_DEBUG
CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
ifdef CONFIG_NO_AES_EXTRAS
CFLAGS += -DCONFIG_NO_AES_UNWRAP
CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1
CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC
CFLAGS += -DCONFIG_NO_AES_DECRYPT
CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK
endif
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
verify_config:
@if [ ! -r .config ]; then \
echo 'Building hostapd requires a configuration file'; \
echo '(.config). See README for more instructions. You can'; \
echo 'run "cp defconfig .config" to create an example'; \
echo 'configuration.'; \
exit 1; \
fi
install: all
for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
hostapd: $(OBJS)
$(CC) -o hostapd $(OBJS) $(LIBS)
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
hostapd_cli: $(OBJS_c)
$(CC) -o hostapd_cli $(OBJS_c)
NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o
NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
ifdef TLS_FUNCS
LIBS_n += -lcrypto
endif
nt_password_hash: $(NOBJS)
$(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
hlr_auc_gw: $(HOBJS)
$(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
clean:
$(MAKE) -C ../src clean
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
rm -f *.d
%.eps: %.fig
fig2dev -L eps $*.fig $*.eps
%.png: %.fig
fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
> $*.png
docs-pics: doc/hostapd.png doc/hostapd.eps
docs: docs-pics
(cd ..; doxygen hostapd/doc/doxygen.full; cd hostapd)
$(MAKE) -C doc/latex
cp doc/latex/refman.pdf hostapd-devel.pdf
docs-fast: docs-pics
(cd ..; doxygen hostapd/doc/doxygen.fast; cd hostapd)
clean-docs:
rm -rf doc/latex doc/html
rm -f doc/hostapd.{eps,png} hostapd-devel.pdf
TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c
test-milenage: $(TEST_SRC_MILENAGE)
$(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
-DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \
-I../src/crypto -I../src/utils
./test-milenage
rm test-milenage
-include $(OBJS:%.o=%.d)

390
hostapd/README Normal file
View File

@ -0,0 +1,390 @@
hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
Copyright (c) 2002-2009, 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.
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:
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.
Introduction
============
Originally, hostapd was an optional user space component for Host AP
driver. It adds more features to the basic IEEE 802.11 management
included in the kernel driver: using external RADIUS authentication
server for MAC address based access control, IEEE 802.1X Authenticator
and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
Authenticator and dynamic TKIP/CCMP keying.
The current version includes support for other drivers, an integrated
EAP server (i.e., allow full authentication without requiring
an external RADIUS authentication server), and RADIUS authentication
server for EAP authentication.
Requirements
------------
Current hardware/software requirements:
- drivers:
Host AP driver for Prism2/2.5/3.
(http://hostap.epitest.fi/)
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
madwifi driver for cards based on Atheros chip set (ar521x)
(http://sourceforge.net/projects/madwifi/)
Please note that you will need to add the correct path for
madwifi driver root directory in .config (see defconfig file for
an example: CFLAGS += -I<path>)
Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
(http://www.prism54.org/)
mac80211-based drivers that support AP mode (with driver=nl80211).
This includes drivers for Atheros (ath9k) and Broadcom (b43)
chipsets.
Any wired Ethernet driver for wired IEEE 802.1X authentication
(experimental code)
FreeBSD -current (with some kernel mods that have not yet been
committed when hostapd v0.3.0 was released)
BSD net80211 layer (e.g., Atheros driver)
Build configuration
-------------------
In order to be able to build hostapd, you will need to create a build
time configuration file, .config that selects which optional
components are included. See defconfig file for example configuration
and list of available options.
IEEE 802.1X
===========
IEEE Std 802.1X-2001 is a standard for port-based network access
control. In case of IEEE 802.11 networks, a "virtual port" is used
between each associated station and the AP. IEEE 802.11 specifies
minimal authentication mechanism for stations, whereas IEEE 802.1X
introduces a extensible mechanism for authenticating and authorizing
users.
IEEE 802.1X uses elements called Supplicant, Authenticator, Port
Access Entity, and Authentication Server. Supplicant is a component in
a station and it performs the authentication with the Authentication
Server. An access point includes an Authenticator that relays the packets
between a Supplicant and an Authentication Server. In addition, it has a
Port Access Entity (PAE) with Authenticator functionality for
controlling the virtual port authorization, i.e., whether to accept
packets from or to the station.
IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
between a Supplicant and an Authenticator are sent using EAP over LAN
(EAPOL) and the Authenticator relays these frames to the Authentication
Server (and similarly, relays the messages from the Authentication
Server to the Supplicant). The Authentication Server can be colocated with the
Authenticator, in which case there is no need for additional protocol
for EAP frame transmission. However, a more common configuration is to
use an external Authentication Server and encapsulate EAP frame in the
frames used by that server. RADIUS is suitable for this, but IEEE
802.1X would also allow other mechanisms.
Host AP driver includes PAE functionality in the kernel driver. It
is a relatively simple mechanism for denying normal frames going to
or coming from an unauthorized port. PAE allows IEEE 802.1X related
frames to be passed between the Supplicant and the Authenticator even
on an unauthorized port.
User space daemon, hostapd, includes Authenticator functionality. It
receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
device that is also used with IEEE 802.11 management frames. The
frames to the Supplicant are sent using the same device.
The normal configuration of the Authenticator would use an external
Authentication Server. hostapd supports RADIUS encapsulation of EAP
packets, so the Authentication Server should be a RADIUS server, like
FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
relays the frames between the Supplicant and the Authentication
Server. It also controls the PAE functionality in the kernel driver by
controlling virtual port authorization, i.e., station-AP
connection, based on the IEEE 802.1X state.
When a station would like to use the services of an access point, it
will first perform IEEE 802.11 authentication. This is normally done
with open systems authentication, so there is no security. After
this, IEEE 802.11 association is performed. If IEEE 802.1X is
configured to be used, the virtual port for the station is set in
Unauthorized state and only IEEE 802.1X frames are accepted at this
point. The Authenticator will then ask the Supplicant to authenticate
with the Authentication Server. After this is completed successfully,
the virtual port is set to Authorized state and frames from and to the
station are accepted.
Host AP configuration for IEEE 802.1X
-------------------------------------
The user space daemon has its own configuration file that can be used to
define AP options. Distribution package contains an example
configuration file (hostapd/hostapd.conf) that can be used as a basis
for configuration. It includes examples of all supported configuration
options and short description of each option. hostapd should be started
with full path to the configuration file as the command line argument,
e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
LAN card, you can use one hostapd process for multiple interfaces by
giving a list of configuration files (one per interface) in the command
line.
hostapd includes a minimal co-located IEEE 802.1X server which can be
used to test IEEE 802.1X authentication. However, it should not be
used in normal use since it does not provide any security. This can be
configured by setting ieee8021x and minimal_eap options in the
configuration file.
An external Authentication Server (RADIUS) is configured with
auth_server_{addr,port,shared_secret} options. In addition,
ieee8021x and own_ip_addr must be set for this mode. With such
configuration, the co-located Authentication Server is not used and EAP
frames will be relayed using EAPOL between the Supplicant and the
Authenticator and RADIUS encapsulation between the Authenticator and
the Authentication Server. Other than this, the functionality is similar
to the case with the co-located Authentication Server.
Authentication Server and Supplicant
------------------------------------
Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
Authentication Server with hostapd Authenticator. FreeRADIUS
(http://www.freeradius.org/) has been successfully tested with hostapd
Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
XP Supplicants. EAP/TLS was used with Xsupplicant and
EAP/MD5-Challenge with Windows XP.
http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
Cisco access point with Host AP driver, hostapd daemon, and a Prism2
card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
EAP/TLS use with WinXP Supplicant.
Automatic WEP key configuration
-------------------------------
EAP/TLS generates a session key that can be used to send WEP keys from
an AP to authenticated stations. The Authenticator in hostapd can be
configured to automatically select a random default/broadcast key
(shared by all authenticated stations) with wep_key_len_broadcast
option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
wep_key_len_unicast option can be used to configure individual unicast
keys for stations. This requires support for individual keys in the
station driver.
WEP keys can be automatically updated by configuring rekeying. This
will improve security of the network since same WEP key will only be
used for a limited period of time. wep_rekey_period option sets the
interval for rekeying in seconds.
WPA/WPA2
========
Features
--------
Supported WPA/IEEE 802.11i features:
- WPA-PSK ("WPA-Personal")
- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
- key management for CCMP, TKIP, WEP104, WEP40
- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
WPA
---
The original security mechanism of IEEE 802.11 standard was not
designed to be strong and has proved to be insufficient for most
networks that require some kind of security. Task group I (Security)
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
to address the flaws of the base standard and has in practice
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
802.11 standard was approved in June 2004 and this amendment is likely
to be published in July 2004.
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
IEEE 802.11i work (draft 3.0) to define a subset of the security
enhancements that can be implemented with existing wlan hardware. This
is called Wi-Fi Protected Access<TM> (WPA). This has now become a
mandatory component of interoperability testing and certification done
by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
site (http://www.wi-fi.org/OpenSection/protected_access.asp).
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
24-bit initialization vector (IV), and CRC32 to protect against packet
forgery. All these choices have proven to be insufficient: key space is
too small against current attacks, RC4 key scheduling is insufficient
(beginning of the pseudorandom stream should be skipped), IV space is
too small and IV reuse makes attacks easier, there is no replay
protection, and non-keyed authentication does not protect against bit
flipping packet data.
WPA is an intermediate solution for the security issues. It uses
Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
compromise on strong security and possibility to use existing
hardware. It still uses RC4 for the encryption like WEP, but with
per-packet RC4 keys. In addition, it implements replay protection,
keyed packet authentication mechanism (Michael MIC).
Keys can be managed using two different mechanisms. WPA can either use
an external authentication server (e.g., RADIUS) and EAP just like
IEEE 802.1X is using or pre-shared keys without need for additional
servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
respectively. Both mechanisms will generate a master session key for
the Authenticator (AP) and Supplicant (client station).
WPA implements a new key handshake (4-Way Handshake and Group Key
Handshake) for generating and exchanging data encryption keys between
the Authenticator and Supplicant. This handshake is also used to
verify that both Authenticator and Supplicant know the master session
key. These handshakes are identical regardless of the selected key
management mechanism (only the method for generating master session
key changes).
IEEE 802.11i / WPA2
-------------------
The design for parts of IEEE 802.11i that were not included in WPA has
finished (May 2004) and this amendment to IEEE 802.11 was approved in
June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
version of WPA called WPA2. This includes, e.g., support for more
robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
to replace TKIP and optimizations for handoff (reduced number of
messages in initial key handshake, pre-authentication, and PMKSA caching).
Some wireless LAN vendors are already providing support for CCMP in
their WPA products. There is no "official" interoperability
certification for CCMP and/or mixed modes using both TKIP and CCMP, so
some interoperability issues can be expected even though many
combinations seem to be working with equipment from different vendors.
Testing for WPA2 is likely to start during the second half of 2004.
hostapd configuration for WPA/WPA2
----------------------------------
TODO
# 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.
# 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.
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
# and/or WPA2 (full IEEE 802.11i/RSN):
# bit0 = WPA
# bit1 = IEEE 802.11i/RSN (WPA2)
#wpa=1
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
#wpa_passphrase=secret passphrase
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space.
#wpa_key_mgmt=WPA-PSK WPA-EAP
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
# (unicast packets). This is a space separated list of algorithms:
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
# is automatically selected based on this configuration. If only CCMP is
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
# TKIP will be used as the group cipher.
#wpa_pairwise=TKIP CCMP
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
# seconds.
#wpa_group_rekey=600
# Time interval for rekeying GMK (master key used internally to generate GTKs
# (in seconds).
#wpa_gmk_rekey=86400
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
# authentication and key handshake before actually associating with a new AP.
#rsn_preauth=1
#
# Space separated list of interfaces from which pre-authentication frames are
# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
# interface that are used for connections to other APs. This could include
# wired interfaces and WDS links. The normal wireless data interface towards
# associated stations (e.g., wlan0) should not be added, since
# pre-authentication is only used with APs other than the currently associated
# one.
#rsn_preauth_interfaces=eth0

232
hostapd/README-WPS Normal file
View File

@ -0,0 +1,232 @@
hostapd and Wi-Fi Protected Setup (WPS)
=======================================
This document describes how the WPS implementation in hostapd can be
configured and how an external component on an AP (e.g., web UI) is
used to enable enrollment of client devices.
Introduction to WPS
-------------------
Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
wireless network. It allows automated generation of random keys (WPA
passphrase/PSK) and configuration of an access point and client
devices. WPS includes number of methods for setting up connections
with PIN method and push-button configuration (PBC) being the most
commonly deployed options.
While WPS can enable more home networks to use encryption in the
wireless network, it should be noted that the use of the PIN and
especially PBC mechanisms for authenticating the initial key setup is
not very secure. As such, use of WPS may not be suitable for
environments that require secure network access without chance for
allowing outsiders to gain access during the setup phase.
WPS uses following terms to describe the entities participating in the
network setup:
- access point: the WLAN access point
- Registrar: a device that control a network and can authorize
addition of new devices); this may be either in the AP ("internal
Registrar") or in an external device, e.g., a laptop, ("external
Registrar")
- Enrollee: a device that is being authorized to use the network
It should also be noted that the AP and a client device may change
roles (i.e., AP acts as an Enrollee and client device as a Registrar)
when WPS is used to configure the access point.
More information about WPS is available from Wi-Fi Alliance:
http://www.wi-fi.org/wifi-protected-setup
hostapd implementation
----------------------
hostapd includes an optional WPS component that can be used as an
internal WPS Registrar to manage addition of new WPS enabled clients
to the network. In addition, WPS Enrollee functionality in hostapd can
be used to allow external WPS Registrars to configure the access
point, e.g., for initial network setup. In addition, hostapd can proxy a
WPS registration between a wireless Enrollee and an external Registrar
(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
hostapd configuration
---------------------
WPS is an optional component that needs to be enabled in hostapd build
configuration (.config). Here is an example configuration that
includes WPS support and uses madwifi driver interface:
CONFIG_DRIVER_MADWIFI=y
CFLAGS += -I/usr/src/madwifi-0.9.3
CONFIG_EAP=y
CONFIG_WPS=y
CONFIG_WPS_UPNP=y
Following section shows an example runtime configuration
(hostapd.conf) that enables WPS:
# Configure the driver and network interface
driver=madwifi
interface=ath0
# WPA2-Personal configuration for the AP
ssid=wps-test
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
# Default WPA passphrase for legacy (non-WPS) clients
wpa_passphrase=12345678
# Enable random per-device PSK generation for WPS clients
# Please note that the file has to exists for hostapd to start (i.e., create an
# empty file as a starting point).
wpa_psk_file=/etc/hostapd.psk
# Enable control interface for PBC/PIN entry
ctrl_interface=/var/run/hostapd
# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
eap_server=1
# WPS configuration (AP configured, do not allow external WPS Registrars)
wps_state=2
ap_setup_locked=1
# If UUID is not configured, it will be generated based on local MAC address.
uuid=87654321-9abc-def0-1234-56789abc0000
wps_pin_requests=/var/run/hostapd.pin-req
device_name=Wireless AP
manufacturer=Company
model_name=WAP
model_number=123
serial_number=12345
device_type=6-0050F204-1
os_version=01020300
config_methods=label display push_button keypad
# if external Registrars are allowed, UPnP support could be added:
#upnp_iface=br0
#friendly_name=WPS Access Point
External operations
-------------------
WPS requires either a device PIN code (usually, 8-digit number) or a
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.
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
with a device password (PIN) for this Enrollee. This is an operation
that requires user interaction (assuming there are no pre-configured
PINs on the AP for a set of Enrollee).
The PIN request with information about the device is appended to the
wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
addition, hostapd control interface event is sent as a notification of
a new device. The AP could use, e.g., a web UI for showing active
Enrollees to the user and request a PIN for an Enrollee.
The PIN request file has one line for every Enrollee that connected to
the AP, but for which there was no PIN. Following information is
provided for each Enrollee (separated with tabulators):
- timestamp (seconds from 1970-01-01)
- Enrollee UUID
- MAC address
- Device name
- Manufacturer
- Model Name
- Model Number
- Serial Number
- Device category
Example line in the /var/run/hostapd.pin-req file:
1200188391 53b63a98-d29e-4457-a2ed-094d7e6a669c Intel(R) Centrino(R) Intel Corporation Intel(R) Centrino(R) - - 1-0050F204-1
Control interface data:
WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
For example:
<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
When the user enters a PIN for a pending Enrollee, e.g., on the web
UI), hostapd needs to be notified of the new PIN over the control
interface. This can be done either by using the UNIX domain socket
-based control interface directly (src/common/wpa_ctrl.c provides
helper functions for using the interface) or by calling hostapd_cli.
Example command to add a PIN (12345670) for an Enrollee:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
If the UUID-E is not available (e.g., Enrollee waits for the Registrar
to be selected before connecting), wildcard UUID may be used to allow the PIN to be used once with any UUID:
hostapd_cli wps_pin any 12345670
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
client device and the client can then use that key to connect to the
AP to access the network.
If the AP includes a pushbutton, WPS PBC mode can be used. It is
enabled by pushing a button on both the AP and the client at about the
same time (2 minute window). hostapd needs to be notified about the AP
button pushed event over the control interface, e.g., by calling
hostapd_cli:
hostapd_cli wps_pbc
At this point, the client has two minutes to complete WPS negotiation
which will generate a new WPA PSK in the same way as the PIN method
described above.
Credential generation and configuration changes
-----------------------------------------------
By default, hostapd generates credentials for Enrollees and processing
AP configuration updates internally. However, it is possible to
control these operations from external programs, if desired.
The internal credential generation can be disabled with
skip_cred_build=1 option in the configuration. extra_cred option will
then need to be used to provide pre-configured Credential attribute(s)
for hostapd to use. The exact data from this binary file will be sent,
i.e., it will have to include valid WPS attributes. extra_cred can
also be used to add additional networks if the Registrar is used to
configure credentials for multiple networks.
Processing of received configuration updates can be disabled with
wps_cred_processing=1 option. When this is used, an external program
is responsible for creating hostapd configuration files and processing
configuration updates based on messages received from hostapd over
control interface. This will also include the initial configuration on
first successful registration if the AP is initially set in
unconfigured state.
Following control interface messages are sent out for external programs:
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
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.
WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
For example:
<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
This can be used to update the externally stored AP configuration and
then update hostapd configuration (followed by restarting of hostapd).

510
hostapd/accounting.c Normal file
View File

@ -0,0 +1,510 @@
/*
* hostapd / RADIUS Accounting
* Copyright (c) 2002-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.
*/
#include "includes.h"
#include "hostapd.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "eloop.h"
#include "accounting.h"
#include "ieee802_1x.h"
#include "driver.h"
/* Default interval in seconds for polling TX/RX octets from the driver if
* STA is not using interim accounting. This detects wrap arounds for
* 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 struct radius_msg * accounting_msg(struct hostapd_data *hapd,
struct sta_info *sta,
int status_type)
{
struct radius_msg *msg;
char buf[128];
u8 *val;
size_t len;
int i;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
if (msg == NULL) {
printf("Could not create net RADIUS packet\n");
return NULL;
}
if (sta) {
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
os_snprintf(buf, sizeof(buf), "%08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Acct-Session-Id\n");
goto fail;
}
} else {
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
printf("Could not add Acct-Status-Type\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
printf("Could not add Acct-Authentic\n");
goto fail;
}
if (sta) {
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
if (!val) {
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
MAC2STR(sta->addr));
val = (u8 *) buf;
len = os_strlen(buf);
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
len)) {
printf("Could not add User-Name\n");
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");
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);
if (val == NULL)
break;
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
val, len)) {
printf("Could not add Class\n");
goto fail;
}
}
}
return msg;
fail:
radius_msg_free(msg);
os_free(msg);
return NULL;
}
static int accounting_sta_update_stats(struct hostapd_data *hapd,
struct sta_info *sta,
struct hostap_sta_driver_data *data)
{
if (hostapd_read_sta_data(hapd, data, sta->addr))
return -1;
if (sta->last_rx_bytes > data->rx_bytes)
sta->acct_input_gigawords++;
if (sta->last_tx_bytes > data->tx_bytes)
sta->acct_output_gigawords++;
sta->last_rx_bytes = data->rx_bytes;
sta->last_tx_bytes = data->tx_bytes;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
"Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
"Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
sta->last_rx_bytes, sta->acct_input_gigawords,
sta->last_tx_bytes, sta->acct_output_gigawords);
return 0;
}
static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
int interval;
if (sta->acct_interim_interval) {
accounting_sta_interim(hapd, sta);
interval = sta->acct_interim_interval;
} else {
struct hostap_sta_driver_data data;
accounting_sta_update_stats(hapd, sta, &data);
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
}
eloop_register_timeout(interval, 0, accounting_interim_update,
hapd, sta);
}
/**
* accounting_sta_start - Start STA accounting
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
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);
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hostapd_sta_clear_stats(hapd, sta->addr);
if (!hapd->conf->radius->acct_server)
return;
if (sta->acct_interim_interval)
interval = sta->acct_interim_interval;
else
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
eloop_register_timeout(interval, 0, accounting_interim_update,
hapd, sta);
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
if (msg)
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
sta->acct_session_started = 1;
}
static void accounting_sta_report(struct hostapd_data *hapd,
struct sta_info *sta, int stop)
{
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
u32 gigawords;
if (!hapd->conf->radius->acct_server)
return;
msg = accounting_msg(hapd, sta,
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
if (!msg) {
printf("Could not create RADIUS Accounting message\n");
return;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
time(NULL) - sta->acct_session_start)) {
printf("Could not add Acct-Session-Time\n");
goto fail;
}
if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_PACKETS,
data.rx_packets)) {
printf("Could not add Acct-Input-Packets\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
data.tx_packets)) {
printf("Could not add Acct-Output-Packets\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
data.rx_bytes)) {
printf("Could not add Acct-Input-Octets\n");
goto fail;
}
gigawords = sta->acct_input_gigawords;
#if __WORDSIZE == 64
gigawords += data.rx_bytes >> 32;
#endif
if (gigawords &&
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Input-Gigawords\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
data.tx_bytes)) {
printf("Could not add Acct-Output-Octets\n");
goto fail;
}
gigawords = sta->acct_output_gigawords;
#if __WORDSIZE == 64
gigawords += data.tx_bytes >> 32;
#endif
if (gigawords &&
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Output-Gigawords\n");
goto fail;
}
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
time(NULL))) {
printf("Could not add Event-Timestamp\n");
goto fail;
}
if (eloop_terminated())
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
if (stop && cause &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
cause)) {
printf("Could not add Acct-Terminate-Cause\n");
goto fail;
}
radius_client_send(hapd->radius, msg,
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
sta->addr);
return;
fail:
radius_msg_free(msg);
os_free(msg);
}
/**
* accounting_sta_interim - Send a interim STA accounting report
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
}
/**
* accounting_sta_stop - Stop STA accounting
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started) {
accounting_sta_report(hapd, sta, 1);
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"stopped accounting session %08X-%08X",
sta->acct_session_id_hi,
sta->acct_session_id_lo);
sta->acct_session_started = 0;
}
}
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
if (hapd->acct_session_id_lo == 0) {
hapd->acct_session_id_hi++;
}
sta->acct_session_id_hi = hapd->acct_session_id_hi;
}
/**
* accounting_receive - Process the RADIUS frames from Accounting Server
* @msg: RADIUS response message
* @req: RADIUS request message
* @shared_secret: RADIUS shared secret
* @shared_secret_len: Length of shared_secret in octets
* @data: Context data (struct hostapd_data *)
* Returns: Processing status
*/
static RadiusRxResult
accounting_receive(struct radius_msg *msg, struct radius_msg *req,
const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
printf("Unknown RADIUS message code\n");
return RADIUS_RX_UNKNOWN;
}
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
printf("Incoming RADIUS packet did not have correct "
"Authenticator - dropped\n");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
return RADIUS_RX_PROCESSED;
}
static void accounting_report_state(struct hostapd_data *hapd, int on)
{
struct radius_msg *msg;
if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
return;
/* Inform RADIUS server that accounting will start/stop so that the
* server can close old accounting sessions. */
msg = accounting_msg(hapd, NULL,
on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
if (!msg)
return;
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
{
printf("Could not add Acct-Terminate-Cause\n");
radius_msg_free(msg);
os_free(msg);
return;
}
radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
}
/**
* accounting_init: Initialize accounting
* @hapd: hostapd BSS data
* Returns: 0 on success, -1 on failure
*/
int accounting_init(struct hostapd_data *hapd)
{
/* 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);
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
return -1;
accounting_report_state(hapd, 1);
return 0;
}
/**
* accounting_deinit: Deinitilize accounting
* @hapd: hostapd BSS data
*/
void accounting_deinit(struct hostapd_data *hapd)
{
accounting_report_state(hapd, 0);
}
int accounting_reconfig(struct hostapd_data *hapd,
struct hostapd_config *oldconf)
{
if (!hapd->radius_client_reconfigured)
return 0;
accounting_deinit(hapd);
return accounting_init(hapd);
}

26
hostapd/accounting.h Normal file
View File

@ -0,0 +1,26 @@
/*
* 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.
*/
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_interim(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);
void accounting_deinit(struct hostapd_data *hapd);
int accounting_reconfig(struct hostapd_data *hapd,
struct hostapd_config *oldconf);
#endif /* ACCOUNTING_H */

139
hostapd/ap.h Normal file
View File

@ -0,0 +1,139 @@
/*
* hostapd / Station table data structures
* Copyright (c) 2002-2008, 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.
*/
#ifndef AP_H
#define AP_H
#ifdef CONFIG_IEEE80211N
#include "ieee802_11_defs.h"
#endif /* CONFIG_IEEE80211N */
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
#define WLAN_STA_PS BIT(2)
#define WLAN_STA_TIM BIT(3)
#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
#define WLAN_STA_PREAUTH BIT(8)
#define WLAN_STA_WME BIT(9)
#define WLAN_STA_MFP BIT(10)
#define WLAN_STA_HT BIT(11)
#define WLAN_STA_WPS BIT(12)
#define WLAN_STA_MAYBE_WPS BIT(13)
#define WLAN_STA_NONERP BIT(31)
/* Maximum number of supported rates (from both Supported Rates and Extended
* Supported Rates IEs). */
#define WLAN_SUPP_RATES_MAX 32
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
u8 addr[6];
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
u32 flags;
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
int supported_rates_len;
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
unsigned int ht_20mhz_set:1;
u16 auth_alg;
u8 previous_ap[6];
enum {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
} timeout_next;
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
/* IEEE 802.11f (IAPP) related data */
struct ieee80211_mgmt *last_assoc_req;
u32 acct_session_id_hi;
u32 acct_session_id_lo;
time_t acct_session_start;
int acct_session_started;
int acct_terminate_cause; /* Acct-Terminate-Cause */
int acct_interim_interval; /* Acct-Interim-Interval */
unsigned long last_rx_bytes;
unsigned long last_tx_bytes;
u32 acct_input_gigawords; /* Acct-Input-Gigawords */
u32 acct_output_gigawords; /* Acct-Output-Gigawords */
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
struct wpa_state_machine *wpa_sm;
struct rsn_preauth_interface *preauth_iface;
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
#ifdef CONFIG_IEEE80211N
struct ht_cap_ie ht_capabilities; /* IEEE 802.11n capabilities */
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_time sa_query_start;
#endif /* CONFIG_IEEE80211W */
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
};
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
* (8802.11 limitation) */
#define MAX_AID_TABLE_SIZE 128
#define STA_HASH_SIZE 256
#define STA_HASH(sta) (sta[5])
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
* 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
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
#define AP_MAX_INACTIVITY (5 * 60)
#define AP_DISASSOC_DELAY (1)
#define AP_DEAUTH_DELAY (1)
/* Number of seconds to keep STA entry with Authenticated flag after it has
* been disassociated. */
#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
/* Number of seconds to keep STA entry after it has been deauthenticated. */
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
#endif /* AP_H */

501
hostapd/ap_list.c Normal file
View File

@ -0,0 +1,501 @@
/*
* hostapd / AP table
* Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
* 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "eloop.h"
#include "ap_list.h"
#include "hw_features.h"
#include "beacon.h"
struct ieee80211_frame_info {
u32 version;
u32 length;
u64 mactime;
u64 hosttime;
u32 phytype;
u32 channel;
u32 datarate;
u32 antenna;
u32 priority;
u32 ssi_type;
u32 ssi_signal;
u32 ssi_noise;
u32 preamble;
u32 encoding;
/* Note: this structure is otherwise identical to capture format used
* in linux-wlan-ng, but this additional field is used to provide meta
* data about the frame to hostapd. This was the easiest method for
* providing this information, but this might change in the future. */
u32 msg_type;
} __attribute__ ((packed));
enum ieee80211_phytype {
ieee80211_phytype_fhss_dot11_97 = 1,
ieee80211_phytype_dsss_dot11_97 = 2,
ieee80211_phytype_irbaseband = 3,
ieee80211_phytype_dsss_dot11_b = 4,
ieee80211_phytype_pbcc_dot11_b = 5,
ieee80211_phytype_ofdm_dot11_g = 6,
ieee80211_phytype_pbcc_dot11_g = 7,
ieee80211_phytype_ofdm_dot11_a = 8,
ieee80211_phytype_dsss_dot11_turbog = 255,
ieee80211_phytype_dsss_dot11_turbo = 256,
};
/* AP list is a double linked list with head->prev pointing to the end of the
* list and tail->next = NULL. Entries are moved to the head of the list
* whenever a beacon has been received from the AP in question. The tail entry
* in this link will thus be the least recently used entry. */
static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
/* TODO: could send a notification message to an external program that
* would then determine whether a rogue AP has been detected */
}
static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
/* TODO: could send a notification message to an external program */
}
static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
{
int i;
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
iface->conf->channel != ap->channel)
return 0;
if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
return 1;
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
int rate = (ap->supported_rates[i] & 0x7f) * 5;
if (rate == 60 || rate == 90 || rate > 110)
return 0;
}
return 1;
}
#ifdef CONFIG_IEEE80211N
static int ap_list_beacon_olbc_ht(struct hostapd_iface *iface,
struct ap_info *ap)
{
return !ap->ht_support;
}
#endif /* CONFIG_IEEE80211N */
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
{
struct ap_info *s;
s = iface->ap_hash[STA_HASH(ap)];
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
s = s->hnext;
return s;
}
static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
{
if (iface->ap_list) {
ap->prev = iface->ap_list->prev;
iface->ap_list->prev = ap;
} else
ap->prev = ap;
ap->next = iface->ap_list;
iface->ap_list = ap;
}
static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
{
if (iface->ap_list == ap)
iface->ap_list = ap->next;
else
ap->prev->next = ap->next;
if (ap->next)
ap->next->prev = ap->prev;
else if (iface->ap_list)
iface->ap_list->prev = ap->prev;
}
static void ap_ap_iter_list_add(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list) {
ap->iter_prev = iface->ap_iter_list->iter_prev;
iface->ap_iter_list->iter_prev = ap;
} else
ap->iter_prev = ap;
ap->iter_next = iface->ap_iter_list;
iface->ap_iter_list = ap;
}
static void ap_ap_iter_list_del(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list == ap)
iface->ap_iter_list = ap->iter_next;
else
ap->iter_prev->iter_next = ap->iter_next;
if (ap->iter_next)
ap->iter_next->iter_prev = ap->iter_prev;
else if (iface->ap_iter_list)
iface->ap_iter_list->iter_prev = ap->iter_prev;
}
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
iface->ap_hash[STA_HASH(ap->addr)] = ap;
}
static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
{
struct ap_info *s;
s = iface->ap_hash[STA_HASH(ap->addr)];
if (s == NULL) return;
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
return;
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
printf("AP: could not remove AP " MACSTR " from hash table\n",
MAC2STR(ap->addr));
}
static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
}
static void hostapd_free_aps(struct hostapd_iface *iface)
{
struct ap_info *ap, *prev;
ap = iface->ap_list;
while (ap) {
prev = ap;
ap = ap->next;
ap_free_ap(iface, prev);
}
iface->ap_list = NULL;
}
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data)
{
struct ap_info *s;
int ret = 0;
s = iface->ap_list;
while (s) {
ret = func(s, data);
if (ret)
break;
s = s->next;
}
return ret;
}
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
{
struct ap_info *ap;
ap = os_zalloc(sizeof(struct ap_info));
if (ap == NULL)
return NULL;
/* initialize AP info data */
os_memcpy(ap->addr, addr, ETH_ALEN);
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
MACSTR " from AP table", MAC2STR(ap->prev->addr));
if (iface->conf->passive_scan_interval > 0)
ap_list_expired_ap(iface, ap->prev);
ap_free_ap(iface, ap->prev);
}
return ap;
}
void ap_list_process_beacon(struct hostapd_iface *iface,
struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
int new_ap = 0;
size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
return;
ap = ap_get_ap(iface, mgmt->bssid);
if (!ap) {
ap = ap_ap_add(iface, mgmt->bssid);
if (!ap) {
printf("Failed to allocate AP information entry\n");
return;
}
new_ap = 1;
}
ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
if (elems->ssid) {
len = elems->ssid_len;
if (len >= sizeof(ap->ssid))
len = sizeof(ap->ssid) - 1;
os_memcpy(ap->ssid, elems->ssid, len);
ap->ssid[len] = '\0';
ap->ssid_len = len;
}
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);
}
ap->wpa = elems->wpa_ie != NULL;
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
ap->erp = -1;
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
else if (fi)
ap->channel = fi->channel;
if (elems->ht_capabilities)
ap->ht_support = 1;
else
ap->ht_support = 0;
ap->num_beacons++;
time(&ap->last_beacon);
if (fi) {
ap->phytype = fi->phytype;
ap->ssi_signal = fi->ssi_signal;
ap->datarate = fi->datarate;
}
if (new_ap) {
if (iface->conf->passive_scan_interval > 0)
ap_list_new_ap(iface, ap);
} else if (ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
* oldest entry is always in the end of the list */
ap_ap_list_del(iface, ap);
ap_ap_list_add(iface, ap);
}
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
"protection", MAC2STR(ap->addr));
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && ap_list_beacon_olbc_ht(iface, ap)) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
" - enable protection", MAC2STR(ap->addr));
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(iface);
}
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
time_t now;
struct ap_info *ap;
int set_beacon = 0;
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
if (!iface->ap_list)
return;
time(&now);
/* FIX: it looks like jkm-Purina ended up in busy loop in this
* function. Apparently, something can still cause a loop in the AP
* list.. */
while (iface->ap_list) {
ap = iface->ap_list->prev;
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
now)
break;
if (iface->conf->passive_scan_interval > 0)
ap_list_expired_ap(iface, ap);
ap_free_ap(iface, ap);
}
if (iface->olbc || iface->olbc_ht) {
int olbc = 0;
int olbc_ht = 0;
ap = iface->ap_list;
while (ap && (olbc == 0 || olbc_ht == 0)) {
if (ap_list_beacon_olbc(iface, ap))
olbc = 1;
#ifdef CONFIG_IEEE80211N
if (ap_list_beacon_olbc_ht(iface, ap))
olbc_ht = 1;
#endif /* CONFIG_IEEE80211N */
ap = ap->next;
}
if (!olbc && iface->olbc) {
wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
iface->olbc = 0;
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
ieee802_11_set_beacons(iface);
}
int ap_list_init(struct hostapd_iface *iface)
{
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
return 0;
}
void ap_list_deinit(struct hostapd_iface *iface)
{
eloop_cancel_timeout(ap_list_timer, iface, NULL);
hostapd_free_aps(iface);
}
int ap_list_reconfig(struct hostapd_iface *iface,
struct hostapd_config *oldconf)
{
time_t now;
struct ap_info *ap;
if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
iface->conf->ap_table_expiration_time ==
oldconf->ap_table_expiration_time)
return 0;
time(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
if (iface->num_ap <= iface->conf->ap_table_max_size &&
ap->last_beacon + iface->conf->ap_table_expiration_time >=
now)
break;
if (iface->conf->passive_scan_interval > 0)
ap_list_expired_ap(iface, iface->ap_list->prev);
ap_free_ap(iface, iface->ap_list->prev);
}
return 0;
}

71
hostapd/ap_list.h Normal file
View File

@ -0,0 +1,71 @@
/*
* hostapd / AP table
* Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
* 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.
*/
#ifndef AP_LIST_H
#define AP_LIST_H
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
* entries. iter_next/iter_prev are updated only when adding new BSSes
* and when removing old ones. These should be used when iterating
* through the table in a manner that allows beacons to be received
* during the iteration. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
struct ap_info *iter_next; /* next entry in AP iteration list */
struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
u16 beacon_int;
u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
u8 ssid[33];
size_t ssid_len;
int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int phytype; /* .11a / .11b / .11g / Atheros Turbo */
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;
int already_seen; /* whether API call AP-NEW has already fetched
* information about this AP */
};
struct ieee802_11_elems;
struct hostapd_frame_info;
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
struct hostapd_frame_info *fi);
int ap_list_init(struct hostapd_iface *iface);
void ap_list_deinit(struct hostapd_iface *iface);
int ap_list_reconfig(struct hostapd_iface *iface,
struct hostapd_config *oldconf);
#endif /* AP_LIST_H */

467
hostapd/beacon.c Normal file
View File

@ -0,0 +1,467 @@
/*
* 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, 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.
*/
#include "includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include "hostapd.h"
#include "ieee802_11.h"
#include "wpa.h"
#include "wme.h"
#include "beacon.h"
#include "hw_features.h"
#include "driver.h"
#include "sta_info.h"
#include "wps_hostapd.h"
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
if (hapd->iface->current_mode == NULL ||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return 0;
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->num_sta_no_short_preamble > 0)
erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
return erp;
}
static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
{
*eid++ = WLAN_EID_DS_PARAMS;
*eid++ = 1;
*eid++ = hapd->iconf->channel;
return eid;
}
static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
{
if (hapd->iface->current_mode == NULL ||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
/* Set NonERP_present and use_protection bits if there
* are any associated NonERP stations. */
/* TODO: use_protection bit can be set to zero even if
* there are NonERP stations present. This optimization
* might be useful if NonERP stations are "quiet".
* See 802.11g/D6 E-1 for recommended practice.
* In addition, Non ERP present might be set, if AP detects Non ERP
* operation on other APs. */
/* Add ERP Information element */
*eid++ = WLAN_EID_ERP_INFO;
*eid++ = 1;
*eid++ = ieee802_11_erp_info(hapd);
return eid;
}
static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
{
if (end - pos < 3)
return pos;
/* first channel number */
*pos++ = start->chan;
/* number of channels */
*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
/* maximum transmit power level */
*pos++ = start->max_tx_power;
return pos;
}
static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
int max_len)
{
u8 *pos = eid;
u8 *end = eid + max_len;
int i;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *start, *prev;
int chan_spacing = 1;
if (!hapd->iconf->ieee80211d || max_len < 6 ||
hapd->iface->current_mode == NULL)
return eid;
*pos++ = WLAN_EID_COUNTRY;
pos++; /* length will be set later */
os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
pos += 3;
mode = hapd->iface->current_mode;
if (mode->mode == HOSTAPD_MODE_IEEE80211A)
chan_spacing = 4;
start = prev = NULL;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (start && prev &&
prev->chan + chan_spacing == chan->chan &&
start->max_tx_power == chan->max_tx_power) {
prev = chan;
continue; /* can use same entry */
}
if (start) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
}
/* Start new group */
start = prev = chan;
}
if (start) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
}
if ((pos - eid) & 1) {
if (end - pos < 1)
return eid;
*pos++ = 0; /* pad for 16-bit alignment */
}
eid[1] = (pos - eid) - 2;
return pos;
}
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
struct sta_info *sta)
{
const u8 *ie;
size_t ielen;
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
if (ie == NULL || ielen > len)
return eid;
os_memcpy(eid, ie, ielen);
return eid + ielen;
}
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len)
{
struct ieee80211_mgmt *resp;
struct ieee802_11_elems elems;
char *ssid;
u8 *pos, *epos, *ie;
size_t ssid_len, ie_len;
struct sta_info *sta = NULL;
ie = mgmt->u.probe_req.variable;
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
hostapd_wps_probe_req_rx(hapd, mgmt->sa, ie, ie_len);
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
resp = os_zalloc(MAX_PROBERESP_LEN);
if (resp == NULL)
return;
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);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.probe_resp.beacon_int =
host_to_le16(hapd->iconf->beacon_int);
/* hardware or low-level driver will setup seq_ctrl and timestamp */
resp->u.probe_resp.capab_info =
host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
pos += ssid_len;
/* Supported rates */
pos = hostapd_eid_supp_rates(hapd, pos);
/* DS Params */
pos = hostapd_eid_ds_params(hapd, pos);
pos = hostapd_eid_country(hapd, pos, epos - pos);
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
/* Wi-Fi Wireless Multimedia Extensions */
pos = hostapd_eid_wme(hapd, pos);
pos = hostapd_eid_ht_capabilities_info(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
os_memcpy(pos, hapd->wps_probe_resp_ie,
hapd->wps_probe_resp_ie_len);
pos += hapd->wps_probe_resp_ie_len;
}
#endif /* CONFIG_WPS */
if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
perror("handle_probe_req: send");
os_free(resp);
wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
"SSID", MAC2STR(mgmt->sa),
elems.ssid_len == 0 ? "broadcast" : "our");
}
void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct ieee80211_mgmt *head;
u8 *pos, *tail, *tailpos;
int preamble;
u16 capab_info;
size_t head_len, tail_len;
int cts_protection = ((ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION) ? 1 : 0);
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
tailpos = tail = os_malloc(BEACON_TAIL_BUF_SIZE);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
os_free(head);
os_free(tail);
return;
}
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
head->duration = host_to_le16(0);
os_memset(head->da, 0xff, ETH_ALEN);
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
head->u.beacon.beacon_int =
host_to_le16(hapd->iconf->beacon_int);
/* hardware or low-level driver will setup seq_ctrl and timestamp */
capab_info = hostapd_own_capab_info(hapd, NULL, 0);
head->u.beacon.capab_info = host_to_le16(capab_info);
pos = &head->u.beacon.variable[0];
/* SSID */
*pos++ = WLAN_EID_SSID;
if (hapd->conf->ignore_broadcast_ssid == 2) {
/* clear the data, but keep the correct length of the SSID */
*pos++ = hapd->conf->ssid.ssid_len;
os_memset(pos, 0, hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
} else if (hapd->conf->ignore_broadcast_ssid) {
*pos++ = 0; /* empty SSID */
} else {
*pos++ = hapd->conf->ssid.ssid_len;
os_memcpy(pos, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
}
/* Supported rates */
pos = hostapd_eid_supp_rates(hapd, pos);
/* DS Params */
pos = hostapd_eid_ds_params(hapd, pos);
head_len = pos - (u8 *) head;
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos, NULL);
/* Wi-Fi Wireless Multimedia Extensions */
tailpos = hostapd_eid_wme(hapd, tailpos);
#ifdef CONFIG_IEEE80211N
if (hapd->iconf->ieee80211n) {
u8 *ht_capab, *ht_oper;
ht_capab = tailpos;
tailpos = hostapd_eid_ht_capabilities_info(hapd, tailpos);
ht_oper = tailpos;
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
if (tailpos > ht_oper && ht_oper > ht_capab &&
hostapd_set_ht_params(hapd->conf->iface, 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");
}
}
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
os_memcpy(tailpos, hapd->wps_beacon_ie,
hapd->wps_beacon_ie_len);
tailpos += hapd->wps_beacon_ie_len;
}
#endif /* CONFIG_WPS */
tail_len = tailpos > tail ? tailpos - tail : 0;
if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
tail, tail_len))
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail");
os_free(tail);
os_free(head);
if (hostapd_set_cts_protect(hapd, cts_protection))
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
"driver");
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");
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");
}
void ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_set_beacon(iface->bss[i]);
}
#endif /* CONFIG_NATIVE_WINDOWS */

24
hostapd/beacon.h Normal file
View File

@ -0,0 +1,24 @@
/*
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef BEACON_H
#define BEACON_H
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len);
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
#endif /* BEACON_H */

2617
hostapd/config.c Normal file

File diff suppressed because it is too large Load Diff

415
hostapd/config.h Normal file
View File

@ -0,0 +1,415 @@
/*
* hostapd / Configuration file
* Copyright (c) 2003-2007, 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.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "defs.h"
#include "ip_addr.h"
#include "wpa_common.h"
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
typedef u8 macaddr[ETH_ALEN];
struct mac_acl_entry {
macaddr addr;
int vlan_id;
};
struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
#define HOSTAPD_MAX_SSID_LEN 32
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
u8 *key[NUM_WEP_KEYS];
size_t len[NUM_WEP_KEYS];
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
SECURITY_STATIC_WEP = 1,
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4
} secpolicy;
struct hostapd_ssid {
char ssid[HOSTAPD_MAX_SSID_LEN + 1];
size_t ssid_len;
int ssid_set;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
struct hostapd_wep_keys wep;
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct hostapd_wep_keys **dyn_vlan_keys;
size_t max_dyn_vlan_keys;
};
#define VLAN_ID_WILDCARD -1
struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
char ifname[IFNAMSIZ + 1];
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
#define DVLAN_CLEAN_BR 0x1
#define DVLAN_CLEAN_VLAN 0x2
#define DVLAN_CLEAN_VLAN_PORT 0x4
#define DVLAN_CLEAN_WLAN_PORT 0x8
int clean;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
};
#define PMK_LEN 32
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
};
#define EAP_USER_MAX_METHODS 8
struct hostapd_eap_user {
struct hostapd_eap_user *next;
u8 *identity;
size_t identity_len;
struct {
int vendor;
u32 method;
} methods[EAP_USER_MAX_METHODS];
u8 *password;
size_t password_len;
int phase2;
int force_version;
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
#define NUM_TX_QUEUES 8
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_wme_ac_params {
int cwmin;
int cwmax;
int aifs;
int txopLimit; /* in units of 32us */
int admission_control_mandatory;
};
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
unsigned int logger_syslog; /* module bitfield */
unsigned int logger_stdout; /* module bitfield */
char *dump_log_name; /* file name for state dump (SIGUSR1) */
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
struct hostapd_ssid ssid;
char *eap_req_id_text; /* optional displayable message sent with
* EAP Request-Identity */
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
* frames */
enum {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
} macaddr_acl;
struct mac_acl_entry *accept_mac;
int num_accept_mac;
struct mac_acl_entry *deny_mac;
int num_deny_mac;
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W
enum {
NO_IEEE80211W = 0,
IEEE80211W_OPTIONAL = 1,
IEEE80211W_REQUIRED = 2
} ieee80211w;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
int peerkey;
#ifdef CONFIG_IEEE80211R
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r1_key_holder[FT_R1KH_ID_LEN];
u32 r0_key_lifetime;
u32 reassociation_deadline;
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
#endif /* CONFIG_IEEE80211R */
char *ctrl_interface; /* directory for UNIX domain sockets */
gid_t ctrl_interface_gid;
int ctrl_interface_gid_set;
char *ca_cert;
char *server_cert;
char *private_key;
char *private_key_passwd;
int check_crl;
char *dh_file;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
char *eap_fast_a_id_info;
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
int eap_sim_aka_result_ind;
int tnc;
char *radius_server_clients;
int radius_server_auth_port;
int radius_server_ipv6;
char *test_socket; /* UNIX domain socket path for driver_test */
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
* address instead of individual address
* (for driver_wired.c).
*/
int ap_max_inactivity;
int ignore_broadcast_ssid;
int wme_enabled;
struct hostapd_vlan *vlan, *vlan_tail;
macaddr bssid;
/*
* Maximum listen interval that STAs can use when associating with this
* BSS. If a STA tries to use larger value, the association will be
* denied with status code 51.
*/
u16 max_listen_interval;
int okc; /* Opportunistic Key Caching */
int wps_state;
#ifdef CONFIG_WPS
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
char *device_name;
char *manufacturer;
char *model_name;
char *model_number;
char *serial_number;
char *device_type;
char *config_methods;
u8 os_version[4];
char *ap_pin;
int skip_cred_build;
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
u8 *ap_settings;
size_t ap_settings_len;
char *upnp_iface;
char *friendly_name;
char *manufacturer_url;
char *model_description;
char *model_url;
char *upc;
#endif /* CONFIG_WPS */
};
typedef enum {
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
NUM_HOSTAPD_MODES
} hostapd_hw_mode;
/**
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
struct hostapd_bss_config *bss, *last_bss;
size_t num_bss;
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
u8 send_probe_response;
u8 channel;
hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
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;
const struct wpa_driver_ops *driver;
int passive_scan_interval; /* seconds, 0 = disabled */
int passive_scan_listen; /* usec */
int passive_scan_mode;
int ap_table_max_size;
int ap_table_expiration_time;
char country[3]; /* first two octets: country code as described in
* ISO/IEC 3166-1. Third octet:
* ' ' (ascii 32): all environments
* 'O': Outdoor environemnt only
* 'I': Indoor environment only
*/
int ieee80211d;
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
* WME AC parameters, in same order as 802.1D, i.e.
* 0 = BE (best effort)
* 1 = BK (background)
* 2 = VI (video)
* 3 = VO (voice)
*/
struct hostapd_wme_ac_params wme_ac_params[4];
enum {
INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
INTERNAL_BRIDGE_DISABLED = 0,
INTERNAL_BRIDGE_ENABLED = 1
} bridge_packets;
#ifdef CONFIG_IEEE80211N
int ht_op_mode_fixed;
u16 ht_capab;
#endif /* CONFIG_IEEE80211N */
int ieee80211n;
int secondary_channel;
};
int hostapd_mac_comp(const void *a, const void *b);
int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_read(const char *fname);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
const u8 *addr, int *vlan_id);
int hostapd_rate_found(int *list, int rate);
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
struct hostapd_wep_keys *b);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk);
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);
#endif /* CONFIG_H */

560
hostapd/ctrl_iface.c Normal file
View File

@ -0,0 +1,560 @@
/*
* hostapd / UNIX domain socket -based control interface
* 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.
*/
#include "includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <sys/un.h>
#include <sys/stat.h>
#include "hostapd.h"
#include "eloop.h"
#include "config.h"
#include "ieee802_1x.h"
#include "wpa.h"
#include "radius/radius_client.h"
#include "ieee802_11.h"
#include "ctrl_iface.h"
#include "sta_info.h"
#include "accounting.h"
#include "wps_hostapd.h"
struct wpa_ctrl_dst {
struct wpa_ctrl_dst *next;
struct sockaddr_un addr;
socklen_t addrlen;
int debug_level;
int errors;
};
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len);
static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
struct sockaddr_un *from,
socklen_t fromlen)
{
struct wpa_ctrl_dst *dst;
dst = os_zalloc(sizeof(*dst));
if (dst == NULL)
return -1;
os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
dst->next = hapd->ctrl_dst;
hapd->ctrl_dst = dst;
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
(u8 *) from->sun_path, fromlen);
return 0;
}
static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
struct sockaddr_un *from,
socklen_t fromlen)
{
struct wpa_ctrl_dst *dst, *prev = NULL;
dst = hapd->ctrl_dst;
while (dst) {
if (fromlen == dst->addrlen &&
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
0) {
if (prev == NULL)
hapd->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
(u8 *) from->sun_path, fromlen);
return 0;
}
prev = dst;
dst = dst->next;
}
return -1;
}
static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
struct sockaddr_un *from,
socklen_t fromlen,
char *level)
{
struct wpa_ctrl_dst *dst;
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
dst = hapd->ctrl_dst;
while (dst) {
if (fromlen == dst->addrlen &&
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
0) {
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
"level", (u8 *) from->sun_path, fromlen);
dst->debug_level = atoi(level);
return 0;
}
dst = dst->next;
}
return -1;
}
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
int len, res, ret;
if (sta == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
len = 0;
ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
MAC2STR(sta->addr));
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
len += ret;
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
if (res >= 0)
len += res;
res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
return len;
}
static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
}
static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
const char *txtaddr,
char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
int ret;
if (hwaddr_aton(txtaddr, addr)) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
buf, buflen);
}
static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
const char *txtaddr,
char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
int ret;
if (hwaddr_aton(txtaddr, addr) ||
(sta = ap_get_sta(hapd, addr)) == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
const char *txtaddr)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
if (hwaddr_aton(txtaddr, addr))
return -1;
sta = ap_get_sta(hapd, addr);
if (sta)
return 0;
wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
"notification", MAC2STR(addr));
sta = ap_sta_add(hapd, addr);
if (sta == NULL)
return -1;
hostapd_new_assoc_sta(hapd, sta, 0);
return 0;
}
#ifdef CONFIG_IEEE80211W
static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
const char *txtaddr)
{
u8 addr[ETH_ALEN];
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
if (hwaddr_aton(txtaddr, addr))
return -1;
os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
ieee802_11_send_sa_query_req(hapd, addr, trans_id);
return 0;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
{
char *pin = os_strchr(txt, ' ');
if (pin == NULL)
return -1;
*pin++ = '\0';
return hostapd_wps_add_pin(hapd, txt, pin);
}
#endif /* CONFIG_WPS */
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
char buf[256];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
char *reply;
const int reply_size = 4096;
int reply_len;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
perror("recvfrom(ctrl_iface)");
return;
}
buf[res] = '\0';
wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
reply = os_malloc(reply_size);
if (reply == NULL) {
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
fromlen);
return;
}
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
if (reply_len >= 0) {
res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
reply_size - reply_len);
if (res < 0)
reply_len = -1;
else
reply_len += res;
}
if (reply_len >= 0) {
res = ieee802_1x_get_mib(hapd, reply + reply_len,
reply_size - reply_len);
if (res < 0)
reply_len = -1;
else
reply_len += res;
}
if (reply_len >= 0) {
res = radius_client_get_mib(hapd->radius,
reply + reply_len,
reply_size - reply_len);
if (res < 0)
reply_len = -1;
else
reply_len += res;
}
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
reply_size);
} else if (os_strncmp(buf, "STA ", 4) == 0) {
reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
reply_size);
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
reply_size);
} else if (os_strcmp(buf, "ATTACH") == 0) {
if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
reply_len = -1;
} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
buf + 6))
reply_len = -1;
} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
reply_len = -1;
#ifdef CONFIG_IEEE80211W
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
reply_len = -1;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
reply_len = -1;
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
if (hostapd_wps_button_pushed(hapd))
reply_len = -1;
#endif /* CONFIG_WPS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
}
if (reply_len < 0) {
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
os_free(reply);
}
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
{
char *buf;
size_t len;
if (hapd->conf->ctrl_interface == NULL)
return NULL;
len = os_strlen(hapd->conf->ctrl_interface) +
os_strlen(hapd->conf->iface) + 2;
buf = os_malloc(len);
if (buf == NULL)
return NULL;
os_snprintf(buf, len, "%s/%s",
hapd->conf->ctrl_interface, hapd->conf->iface);
buf[len - 1] = '\0';
return buf;
}
static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
const char *txt, size_t len)
{
struct hostapd_data *hapd = ctx;
if (hapd == NULL)
return;
hostapd_ctrl_iface_send(hapd, level, txt, len);
}
int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
hapd->ctrl_sock = -1;
if (hapd->conf->ctrl_interface == NULL)
return 0;
if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
if (errno == EEXIST) {
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
perror("mkdir[ctrl_interface]");
goto fail;
}
}
if (hapd->conf->ctrl_interface_gid_set &&
chown(hapd->conf->ctrl_interface, 0,
hapd->conf->ctrl_interface_gid) < 0) {
perror("chown[ctrl_interface]");
return -1;
}
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
goto fail;
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket(PF_UNIX)");
goto fail;
}
os_memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
fname = hostapd_ctrl_iface_path(hapd);
if (fname == NULL)
goto fail;
os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind(PF_UNIX)");
goto fail;
}
if (hapd->conf->ctrl_interface_gid_set &&
chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
perror("chown[ctrl_interface/ifname]");
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
perror("chmod[ctrl_interface/ifname]");
goto fail;
}
os_free(fname);
hapd->ctrl_sock = s;
eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
NULL);
wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
return 0;
fail:
if (s >= 0)
close(s);
if (fname) {
unlink(fname);
os_free(fname);
}
return -1;
}
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
struct wpa_ctrl_dst *dst, *prev;
if (hapd->ctrl_sock > -1) {
char *fname;
eloop_unregister_read_sock(hapd->ctrl_sock);
close(hapd->ctrl_sock);
hapd->ctrl_sock = -1;
fname = hostapd_ctrl_iface_path(hapd);
if (fname)
unlink(fname);
os_free(fname);
if (hapd->conf->ctrl_interface &&
rmdir(hapd->conf->ctrl_interface) < 0) {
if (errno == ENOTEMPTY) {
wpa_printf(MSG_DEBUG, "Control interface "
"directory not empty - leaving it "
"behind");
} else {
perror("rmdir[ctrl_interface]");
}
}
}
dst = hapd->ctrl_dst;
while (dst) {
prev = dst;
dst = dst->next;
os_free(prev);
}
}
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len)
{
struct wpa_ctrl_dst *dst, *next;
struct msghdr msg;
int idx;
struct iovec io[2];
char levelstr[10];
dst = hapd->ctrl_dst;
if (hapd->ctrl_sock < 0 || dst == NULL)
return;
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
io[0].iov_base = levelstr;
io[0].iov_len = os_strlen(levelstr);
io[1].iov_base = (char *) buf;
io[1].iov_len = len;
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
msg.msg_iovlen = 2;
idx = 0;
while (dst) {
next = dst->next;
if (level >= dst->debug_level) {
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
(u8 *) dst->addr.sun_path, dst->addrlen);
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
idx);
perror("sendmsg");
dst->errors++;
if (dst->errors > 10) {
hostapd_ctrl_iface_detach(
hapd, &dst->addr,
dst->addrlen);
}
} else
dst->errors = 0;
}
idx++;
dst = next;
}
}
#endif /* CONFIG_NATIVE_WINDOWS */

21
hostapd/ctrl_iface.h Normal file
View File

@ -0,0 +1,21 @@
/*
* 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.
*/
#ifndef CTRL_IFACE_H
#define CTRL_IFACE_H
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_H */

144
hostapd/defconfig Normal file
View File

@ -0,0 +1,144 @@
# Example hostapd build time configuration
#
# This file lists the configuration options that are used when building the
# hostapd binary. All lines starting with # are ignored. Configuration option
# lines must be commented out complete, if they are not to be included, i.e.,
# just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cass, these lines should use += in order not
# to override previous values of the variables.
# Driver interface for Host AP driver
CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
# Driver interface for madwifi driver
#CONFIG_DRIVER_MADWIFI=y
#CFLAGS += -I../../madwifi # change to the madwifi source directory
# Driver interface for Prism54 driver
#CONFIG_DRIVER_PRISM54=y
# 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
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
#LIBS += -L/usr/local/lib
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
# IEEE 802.11F/IAPP
CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
# IEEE 802.11w (management frame protection)
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
# Integrated EAP server
CONFIG_EAP=y
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP server
CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP server
CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP server
CONFIG_EAP_PEAP=y
# EAP-GTC for the integrated EAP server
CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP server
CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-AKA' for the integrated EAP server
# This requires CONFIG_EAP_AKA to be enabled, too.
#CONFIG_EAP_AKA_PRIME=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
#CONFIG_EAP_FAST=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE Std 802.11r-2008 (Fast BSS Transition)
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
#CONFIG_IEEE80211N=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

4
hostapd/doc/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
html
latex
hostapd.eps
hostapd.png

View File

@ -0,0 +1,5 @@
/**
\page code_structure Structure of the source code
*/

View File

@ -0,0 +1,66 @@
/**
\page ctrl_iface_page Control interface
hostapd implements a control interface that can be used by
external programs to control the operations of the hostapd
daemon and to get status information and event notifications. There is
a small C library, in a form of a single C file, wpa_ctrl.c, that
provides helper functions to facilitate the use of the control
interface. External programs can link this file into them and then use
the library functions documented in wpa_ctrl.h to interact with
%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
is an example program using this library.
There are multiple mechanisms for inter-process communication. For
example, Linux version of hostapd is using UNIX domain sockets for the
control interface. The use of the functions defined in wpa_ctrl.h can
be used to hide the details of the used IPC from external programs.
\section using_ctrl_iface Using the control interface
External programs, e.g., a GUI or a configuration utility, that need to
communicate with hostapd should link in wpa_ctrl.c. This
allows them to use helper functions to open connection to the control
interface with wpa_ctrl_open() and to send commands with
wpa_ctrl_request().
hostapd uses the control interface for two types of communication:
commands and unsolicited event messages. Commands are a pair of
messages, a request from the external program and a response from
hostapd. These can be executed using wpa_ctrl_request().
Unsolicited event messages are sent by hostapd to the control
interface connection without specific request from the external program
for receiving each message. However, the external program needs to
attach to the control interface with wpa_ctrl_attach() to receive these
unsolicited messages.
If the control interface connection is used both for commands and
unsolicited event messages, there is potential for receiving an
unsolicited message between the command request and response.
wpa_ctrl_request() caller will need to supply a callback, msg_cb,
for processing these messages. Often it is easier to open two
control interface connections by calling wpa_ctrl_open() twice and
then use one of the connections for commands and the other one for
unsolicited messages. This way command request/response pairs will
not be broken by unsolicited messages. wpa_cli is an example of how
to use only one connection for both purposes and wpa_gui demonstrates
how to use two separate connections.
Once the control interface connection is not needed anymore, it should
be closed by calling wpa_ctrl_close(). If the connection was used for
unsolicited event messages, it should be first detached by calling
wpa_ctrl_detach().
\section ctrl_iface_cmds Control interface commands
Following commands can be used with wpa_ctrl_request():
\subsection ctrl_iface_PING PING
This command can be used to test whether hostapd is replying
to the control interface commands. The expected reply is \c PONG if the
connection is open and hostapd is processing commands.
*/

238
hostapd/doc/doxygen.fast Normal file
View File

@ -0,0 +1,238 @@
# Doxyfile 1.4.4
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = hostapd
PROJECT_NUMBER = 0.6.x
OUTPUT_DIRECTORY = hostapd/doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = hostapd \
src/common \
src/crypto \
src/eap_common \
src/eap_server \
src/l2_packet \
src/radius \
src/rsn_supp \
src/tls \
src/utils \
src/wps
FILE_PATTERNS = *.c *.h *.doxygen
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = hostapd/doc
INPUT_FILTER = kerneldoc2doxygen.pl
FILTER_PATTERNS =
FILTER_SOURCE_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 3
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

238
hostapd/doc/doxygen.full Normal file
View File

@ -0,0 +1,238 @@
# Doxyfile 1.4.4
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = hostapd
PROJECT_NUMBER = 0.6.x
OUTPUT_DIRECTORY = hostapd/doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = hostapd \
src/common \
src/crypto \
src/eap_common \
src/eap_server \
src/l2_packet \
src/radius \
src/rsn_supp \
src/tls \
src/utils \
src/wps
FILE_PATTERNS = *.c *.h *.doxygen
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = hostapd/doc
INPUT_FILTER = kerneldoc2doxygen.pl
FILTER_PATTERNS =
FILTER_SOURCE_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 3
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = NO
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = YES

View File

@ -0,0 +1,20 @@
/**
\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
All hardware and driver dependent functionality is in separate C files
that implement defined wrapper functions. Other parts
of the hostapd are designed to be hardware, driver, and operating
system independent.
Driver wrappers need to implement whatever calls are used in the
target operating system/driver for controlling wireless LAN
devices. As an example, in case of Linux, these are mostly some glue
code and ioctl() calls and netlink message parsing for Linux Wireless
Extensions (WE). Since features required for WPA were added only recently to
Linux Wireless Extensions (in version 18), some driver specific code is used
in number of driver interface implementations. These driver dependent parts
can be replaced with generic code in driver_wext.c once the target driver
includes full support for WE-18. After that, all Linux drivers, at
least in theory, could use the same driver wrapper code.
*/

56
hostapd/doc/eap.doxygen Normal file
View File

@ -0,0 +1,56 @@
/**
\page eap_module EAP server implementation
Extensible Authentication Protocol (EAP) is an authentication framework
defined in RFC 3748. hostapd uses a separate code module for EAP server
implementation. This module was designed to use only a minimal set of
direct function calls (mainly, to debug/event functions) in order for
it to be usable in other programs. The design of the EAP
implementation is based loosely on RFC 4137. The state machine is
defined in this RFC and so is the interface between the server state
machine and methods. As such, this RFC provides useful information for
understanding the EAP server implementation in hostapd.
Some of the terminology used in EAP state machine is referring to
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
layer being IEEE 802.1X if EAP module is built for other programs than
%wpa_supplicant. These terms should be understood to refer to the
lower layer as defined in RFC 4137.
\section adding_eap_methods Adding EAP methods
Each EAP method is implemented as a separate module, usually as one C
file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
methods use the same interface between the server state machine and
method specific functions. This allows new EAP methods to be added
without modifying the core EAP state machine implementation.
New EAP methods need to be registered by adding them into the build
(Makefile) and the EAP method registration list in the
eap_server_register_methods() function of eap_methods.c. Each EAP
method should use a build-time configuration option, e.g., EAP_TLS, in
order to make it possible to select which of the methods are included
in the build.
EAP methods must implement the interface defined in eap_i.h. struct
eap_method defines the needed function pointers that each EAP method
must provide. In addition, the EAP type and name are registered using
this structure. This interface is based on section 4.4 of RFC 4137.
It is recommended that the EAP methods would use generic helper
functions, eap_msg_alloc() and eap_hdr_validate() when processing
messages. This allows code sharing and can avoid missing some of the
needed validation steps for received packets. In addition, these
functions make it easier to change between expanded and legacy EAP
header, if needed.
When adding an EAP method that uses a vendor specific EAP type
(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
must be registered by passing vendor id instead of EAP_VENDOR_IETF to
eap_server_method_alloc(). These methods must not try to emulate
expanded types by registering a legacy EAP method for type 254. See
eap_vendor_test.c for an example of an EAP method implementation that
is implemented as an expanded type.
*/

264
hostapd/doc/hostapd.fig Normal file
View File

@ -0,0 +1,264 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
6 1875 4050 2925 4350
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
-6
6 4725 1200 5925 1500
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
-6
6 6000 2700 7200 3225
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
-6
6 6000 4950 7200 5475
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
-6
6 4350 3900 5025 4425
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
-6
6 4275 2550 5100 2850
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
-6
6 6000 3900 7200 4425
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
-6
6 2775 3150 4050 3450
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
-6
6 3450 1200 4575 1500
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
-6
6 3525 7800 5775 8100
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
-6
6 4275 6000 5100 6300
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
-6
6 8175 4725 9225 5025
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
-6
6 9300 4725 10350 5025
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
-6
6 8175 5100 9225 5400
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
-6
6 9300 5100 10350 5400
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
-6
6 8175 5475 9225 5775
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
-6
6 8175 5850 9225 6150
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
-6
6 8175 6225 9225 6525
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
-6
6 9300 5850 10350 6150
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
-6
6 9300 5475 10350 5775
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
-6
6 8175 6600 9675 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
-6
6 8700 3450 9375 3750
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
-6
6 9600 3450 10275 3750
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
-6
6 6000 5775 7200 6300
6 6000 5775 7200 6300
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
-6
4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
-6
6 8100 2250 8925 2775
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
-6
6 3150 5475 4425 5775
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
-6
6 1950 5550 2625 6075
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
-6
6 1875 4725 2925 5250
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
-6
2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
1275 4200 1875 4200
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
4500 2550 3900 1500
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
4800 2550 5400 1500
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
2925 4200 4350 4200
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5025 3900 6000 3000
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5025 4200 6000 4200
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4650 6000 4650 4425
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
6600 4425 6600 4950
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
6600 3225 6600 3900
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
7200 5250 8100 5250
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
9075 4425 9075 3750
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
7200 3000 8700 3525
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4650 3900 4650 2850
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
7200 4125 8700 3675
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
6000 4350 5025 6000
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
6000 3150 4875 6000
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
9900 4425 9900 3750
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
4350 3900
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4350 3900 4050 3450
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4350 4425 4050 5475
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
2250 7200 4200 7800
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
7200 7200 5100 7800
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
2250 6900 2250 6600 7200 6600 7200 6900
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
3225 6900 3225 6600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4200 6900 4200 6600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5175 6900 5175 6600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
6150 6900 6150 6600
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
4650 6600 4650 6300
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
6600 5475 6600 5775
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
5025 4425 6000 5775
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
4800 3900 5925 2550 8100 2550
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
7200 3900 8475 2775
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
8925 2475 9450 2475
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
2325 5550 2325 5250
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
2925 4950 4350 4275
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
2850 4725 5775 2400 8100 2400
4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001

129
hostapd/doc/kerneldoc2doxygen.pl Executable file
View File

@ -0,0 +1,129 @@
#!/usr/bin/perl -w
#
##########################################################################
# Convert kernel-doc style comments to Doxygen comments.
##########################################################################
#
# This script reads a C source file from stdin, and writes
# to stdout. Normal usage:
#
# $ mv file.c file.c.gtkdoc
# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
#
# Or to do the same thing with multiple files:
# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
#
# This script may also be suitable for use as a Doxygen input filter,
# but that has not been tested.
#
# Back up your source files before using this script!!
#
##########################################################################
# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
# (modified for kerneldoc format used in wpa_supplicant)
#
# 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
# or look at http://www.gnu.org/licenses/gpl.html
##########################################################################
##########################################################################
#
# This function converts a single comment from gtk-doc to Doxygen format.
# The parameter does not include the opening or closing lines
# (i.e. given a comment like this:
# "/**\n"
# " * FunctionName:\n"
# " * @foo: This describes the foo parameter\n"
# " * @bar: This describes the bar parameter\n"
# " * @Returns: This describes the return value\n"
# " *\n"
# " * This describes the function.\n"
# " */\n"
# This function gets:
# " * FunctionName:\n"
# " * @foo: This describes the foo parameter\n"
# " * @bar: This describes the bar parameter\n"
# " * @Returns: This describes the return value\n"
# " *\n"
# " * This describes the function.\n"
# And it returns:
# " * This describes the function.\n"
# " *\n"
# " * @param foo This describes the foo parameter\n"
# " * @param bar This describes the bar parameter\n"
# " * @return This describes the return value\n"
# )
#
sub fixcomment {
$t = $_[0];
# " * func: foo" --> "\brief foo\n"
# " * struct bar: foo" --> "\brief foo\n"
# If this fails, not a kernel-doc comment ==> return unmodified.
($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
or return $t;
# " * Returns: foo" --> "\return foo"
$t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
# " * @foo: bar" --> "\param foo bar"
# Handle two common typos: No ":", or "," instead of ":".
$t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
return $t;
}
##########################################################################
# Start of main code
# Read entire stdin into memory - one multi-line string.
$_ = do { local $/; <> };
s{^/\*\n \*}{/\*\* \\file\n\\brief};
s{ \* Copyright}{\\par Copyright\nCopyright};
# Fix any comments like "/*************" so they don't match.
# "/***" ===> "/* *"
s{/\*\*\*}{/\* \*}gs;
# The main comment-detection code.
s{
( # $1 = Open comment
/\*\* # Open comment
(?!\*) # Do not match /*** (redundant due to fixup above).
[\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
)
(.*?) # $2 = Body of comment (multi-line)
( # $3 = Close comment
( # If possible, match the whitespace before the close-comment
(?<=\n) # This part only matches after a newline
[\t ]* # Eat whitespace
)?
\*/ # Close comment
)
}
{
$1 . fixcomment($2) . $3
}gesx;
# ^^^^ Modes: g - Global, match all occurances.
# e - Evaluate the replacement as an expression.
# s - Single-line - allows the pattern to match across newlines.
# x - eXtended pattern, ignore embedded whitespace
# and allow comments.
# Write results to stdout
print $_;

View File

@ -0,0 +1,52 @@
/**
\mainpage Developers' documentation for hostapd
hostapd includes IEEE 802.11 access point management (authentication /
association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
RADIUS authentication server functionality. It can be build with
various configuration option, e.g., a standalone AP management
solution or a RADIUS authentication server with support for number of
EAP methods.
The goal of this documentation and comments in the source code is to
give enough information for other developers to understand how hostapd
has been implemented, how it can be modified, how new drivers can be
supported, and how hostapd can be ported to other operating
systems. If any information is missing, feel free to contact Jouni
Malinen <j@w1.fi> for more information. Contributions as
patch files are also very welcome at the same address. Please note
that hostapd is licensed under dual license, GPLv2 or BSD at user's
choice. All contributions to hostapd are expected to use compatible
licensing terms.
The source code and read-only access to hostapd CVS repository
is available from the project home page at
http://hostap.epitest.fi/hostapd/. This developers' documentation
is also available as a PDF file from
http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
The design goal for hostapd was to use hardware, driver, and
OS independent, portable C code for all WPA functionality. The source
code is divided into separate C files as shown on the \ref
code_structure "code structure page". All hardware/driver specific
functionality is in separate files that implement a \ref
driver_wrapper "well-defined driver API". Information about porting
to different target boards and operating systems is available on
the \ref porting "porting page".
EAPOL (IEEE 802.1X) state machines are implemented as a separate
module that interacts with \ref eap_module "EAP server implementation".
Similarly, RADIUS authentication server is in its own separate module.
Both IEEE 802.1X and RADIUS authentication server can use EAP server
functionality.
hostapd implements a \ref ctrl_iface_page "control interface" that can
be used by external programs to control the operations of the hostapdt
daemon and to get status information and event notifications. There is
a small C library that provides helper functions to facilitate the use
of the control interface. This library can also be used with C++.
\image html hostapd.png "hostapd modules"
\image latex hostapd.eps "hostapd modules" width=15cm
*/

View File

@ -0,0 +1,5 @@
/**
\page porting Porting to different target boards and operating systems
*/

798
hostapd/driver.h Normal file
View File

@ -0,0 +1,798 @@
/*
* hostapd - driver interface definition
* Copyright (c) 2002-2007, 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.
*/
#ifndef DRIVER_H
#define DRIVER_H
struct hostapd_sta_add_params {
const u8 *addr;
u16 aid;
u16 capability;
const u8 *supp_rates;
size_t supp_rates_len;
int flags;
u16 listen_interval;
const struct ht_cap_ie *ht_capabilities;
};
struct hostapd_freq_params {
int mode;
int freq;
int ht_enabled;
int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
* secondary channel below primary, 1 = HT40
* enabled, secondary channel above primary */
};
enum hostapd_driver_if_type {
HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
};
struct wpa_driver_ops {
const char *name; /* as appears in the config file */
void * (*init)(struct hostapd_data *hapd);
void * (*init_bssid)(struct hostapd_data *hapd, const u8 *bssid);
void (*deinit)(void *priv);
int (*wireless_event_init)(void *priv);
void (*wireless_event_deinit)(void *priv);
/**
* set_8021x - enable/disable IEEE 802.1X support
* @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: driver private data
* @enabled: 1 = enable, 0 = disable
*
* Returns: 0 on success, -1 on failure
*
* Configure the kernel driver to enable/disable 802.1X support.
* This may be an empty function if 802.1X support is always enabled.
*/
int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
/**
* set_privacy - enable/disable privacy
* @priv: driver private data
* @enabled: 1 = privacy enabled, 0 = disabled
*
* Return: 0 on success, -1 on failure
*
* Configure privacy.
*/
int (*set_privacy)(const char *ifname, void *priv, int enabled);
int (*set_encryption)(const char *ifname, void *priv, const char *alg,
const u8 *addr, int idx,
const u8 *key, size_t key_len, int txkey);
int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
int idx, u8 *seq);
int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
int idx, u8 *seq);
int (*flush)(void *priv);
int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
size_t elem_len);
int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
const u8 *addr);
int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
size_t data_len, int encrypt, const u8 *own_addr);
int (*sta_deauth)(void *priv, const u8 *addr, int reason);
int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
int (*sta_remove)(void *priv, const u8 *addr);
int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
int len);
int (*set_countermeasures)(void *priv, int enabled);
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
int flags);
int (*set_assoc_ap)(void *priv, const u8 *addr);
/* note: sta_add() is deprecated; use sta_add2() instead */
int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
u16 capability, u8 *supp_rates, size_t supp_rates_len,
int flags, u16 listen_interval);
int (*sta_add2)(const char *ifname, void *priv,
struct hostapd_sta_add_params *params);
int (*get_inact_sec)(void *priv, const u8 *addr);
int (*sta_clear_stats)(void *priv, const u8 *addr);
/* note: set_freq() is deprecated; use set_freq2() instead */
int (*set_freq)(void *priv, int mode, int freq);
int (*set_freq2)(void *priv, struct hostapd_freq_params *freq);
int (*set_rts)(void *priv, int rts);
int (*get_rts)(void *priv, int *rts);
int (*set_frag)(void *priv, int frag);
int (*get_frag)(void *priv, int *frag);
int (*set_retry)(void *priv, int short_retry, int long_retry);
int (*get_retry)(void *priv, int *short_retry, int *long_retry);
int (*sta_set_flags)(void *priv, const u8 *addr,
int total_flags, int flags_or, int flags_and);
int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
int mode);
int (*set_regulatory_domain)(void *priv, unsigned int rd);
int (*set_country)(void *priv, const char *country);
int (*set_ieee80211d)(void *priv, int enabled);
int (*set_beacon)(const char *ifname, void *priv,
u8 *head, size_t head_len,
u8 *tail, size_t tail_len);
/* Configure internal bridge:
* 0 = disabled, i.e., client separation is enabled (no bridging of
* packets between associated STAs
* 1 = enabled, i.e., bridge packets between associated STAs (default)
*/
int (*set_internal_bridge)(void *priv, int value);
int (*set_beacon_int)(void *priv, int value);
int (*set_dtim_period)(const char *ifname, void *priv, int value);
/* Configure broadcast SSID mode:
* 0 = include SSID in Beacon frames and reply to Probe Request frames
* that use broadcast SSID
* 1 = hide SSID from Beacon frames and ignore Probe Request frames for
* broadcast SSID
*/
int (*set_broadcast_ssid)(void *priv, int value);
int (*set_cts_protect)(void *priv, int value);
int (*set_key_tx_rx_threshold)(void *priv, int value);
int (*set_preamble)(void *priv, int value);
int (*set_short_slot_time)(void *priv, int value);
int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
int cw_max, int burst_time);
int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
int (*bss_remove)(void *priv, const char *ifname);
int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
int (*passive_scan)(void *priv, int now, int our_mode_only,
int interval, int _listen, int *channel,
int *last_rx);
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
u16 *num_modes,
u16 *flags);
int (*if_add)(const char *iface, void *priv,
enum hostapd_driver_if_type type, char *ifname,
const u8 *addr);
int (*if_update)(void *priv, enum hostapd_driver_if_type type,
char *ifname, const u8 *addr);
int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
const char *ifname, const u8 *addr);
int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
int vlan_id);
/**
* commit - Optional commit changes handler
* @priv: driver private data
* Returns: 0 on success, -1 on failure
*
* This optional handler function can be registered if the driver
* interface implementation needs to commit changes (e.g., by setting
* network interface up) at the end of initial configuration. If set,
* this handler will be called after initial setup has been completed.
*/
int (*commit)(void *priv);
int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
const u8 *data, size_t data_len);
int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
u32 session_timeout);
int (*set_radius_acl_expire)(void *priv, const u8 *mac);
int (*set_ht_params)(const char *ifname, void *priv,
const u8 *ht_capab, size_t ht_capab_len,
const u8 *ht_oper, size_t ht_oper_len);
int (*set_wps_beacon_ie)(const char *ifname, void *priv,
const u8 *ie, size_t len);
int (*set_wps_probe_resp_ie)(const char *ifname, void *priv,
const u8 *ie, size_t len);
};
static inline void *
hostapd_driver_init(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->init == NULL)
return NULL;
return hapd->driver->init(hapd);
}
static inline void *
hostapd_driver_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
{
if (hapd->driver == NULL || hapd->driver->init_bssid == NULL)
return NULL;
return hapd->driver->init_bssid(hapd, bssid);
}
static inline void
hostapd_driver_deinit(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->deinit == NULL)
return;
hapd->driver->deinit(hapd->drv_priv);
}
static inline int
hostapd_wireless_event_init(struct hostapd_data *hapd)
{
if (hapd->driver == NULL ||
hapd->driver->wireless_event_init == NULL)
return 0;
return hapd->driver->wireless_event_init(hapd->drv_priv);
}
static inline void
hostapd_wireless_event_deinit(struct hostapd_data *hapd)
{
if (hapd->driver == NULL ||
hapd->driver->wireless_event_deinit == NULL)
return;
hapd->driver->wireless_event_deinit(hapd->drv_priv);
}
static inline int
hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
return 0;
return hapd->driver->set_ieee8021x(ifname, hapd->drv_priv, enabled);
}
static inline int
hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
return 0;
return hapd->driver->set_privacy(hapd->conf->iface, hapd->drv_priv,
enabled);
}
static inline int
hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
const char *alg, const u8 *addr, int idx,
u8 *key, size_t key_len, int txkey)
{
if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
return 0;
return hapd->driver->set_encryption(ifname, hapd->drv_priv, alg, addr,
idx, key, key_len, txkey);
}
static inline int
hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq)
{
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
return 0;
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
seq);
}
static inline int
hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq)
{
if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
return -1;
return hapd->driver->get_seqnum_igtk(ifname, hapd->drv_priv, addr, idx,
seq);
}
static inline int
hostapd_flush(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->flush == NULL)
return 0;
return hapd->driver->flush(hapd->drv_priv);
}
static inline int
hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len)
{
if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
return 0;
return hapd->driver->set_generic_elem(hapd->conf->iface,
hapd->drv_priv, elem, elem_len);
}
static inline 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 inline 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->send_eapol == NULL)
return 0;
return hapd->driver->send_eapol(hapd->drv_priv, addr, data, data_len,
encrypt, hapd->own_addr);
}
static inline int
hostapd_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, addr, reason);
}
static inline 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, addr, reason);
}
static inline int
hostapd_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_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
return 0;
return hapd->driver->get_ssid(hapd->conf->iface, hapd->drv_priv, buf,
len);
}
static inline int
hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
return 0;
return hapd->driver->set_ssid(hapd->conf->iface, hapd->drv_priv, buf,
len);
}
static inline int
hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
int flags)
{
if (hapd->driver == NULL || hapd->driver->send_mgmt_frame == NULL)
return 0;
return hapd->driver->send_mgmt_frame(hapd->drv_priv, msg, len, flags);
}
static inline int
hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
return 0;
return hapd->driver->set_assoc_ap(hapd->drv_priv, addr);
}
static inline int
hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
return 0;
return hapd->driver->set_countermeasures(hapd->drv_priv, enabled);
}
static inline int
hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
u16 aid, u16 capability, const u8 *supp_rates,
size_t supp_rates_len, int flags, u16 listen_interval,
const struct ht_cap_ie *ht_capabilities)
{
if (hapd->driver == NULL)
return 0;
if (hapd->driver->sta_add2) {
struct hostapd_sta_add_params params;
os_memset(&params, 0, sizeof(params));
params.addr = addr;
params.aid = aid;
params.capability = capability;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.flags = flags;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capabilities;
return hapd->driver->sta_add2(ifname, hapd->drv_priv, &params);
}
if (hapd->driver->sta_add == NULL)
return 0;
return hapd->driver->sta_add(ifname, hapd->drv_priv, addr, aid,
capability, (u8 *) supp_rates,
supp_rates_len,
flags, listen_interval);
}
static inline int
hostapd_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_set_freq(struct hostapd_data *hapd, int mode, int freq, int ht_enabled,
int sec_channel_offset)
{
if (hapd->driver == NULL)
return 0;
if (hapd->driver->set_freq2) {
struct hostapd_freq_params data;
os_memset(&data, 0, sizeof(data));
data.mode = mode;
data.freq = freq;
data.ht_enabled = ht_enabled;
data.sec_channel_offset = sec_channel_offset;
return hapd->driver->set_freq2(hapd->drv_priv, &data);
}
if (hapd->driver->set_freq == NULL)
return 0;
return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
}
static inline int
hostapd_set_rts(struct hostapd_data *hapd, int rts)
{
if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
return 0;
return hapd->driver->set_rts(hapd->drv_priv, rts);
}
static inline int
hostapd_get_rts(struct hostapd_data *hapd, int *rts)
{
if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
return 0;
return hapd->driver->get_rts(hapd->drv_priv, rts);
}
static inline int
hostapd_set_frag(struct hostapd_data *hapd, int frag)
{
if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
return 0;
return hapd->driver->set_frag(hapd->drv_priv, frag);
}
static inline int
hostapd_get_frag(struct hostapd_data *hapd, int *frag)
{
if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
return 0;
return hapd->driver->get_frag(hapd->drv_priv, frag);
}
static inline int
hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
{
if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
return 0;
return hapd->driver->set_retry(hapd->drv_priv, short_retry,
long_retry);
}
static inline int
hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
{
if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
return 0;
return hapd->driver->get_retry(hapd->drv_priv, short_retry,
long_retry);
}
static inline int
hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and)
{
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
}
static inline 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);
}
static inline int
hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
{
if (hapd->driver == NULL ||
hapd->driver->set_regulatory_domain == NULL)
return 0;
return hapd->driver->set_regulatory_domain(hapd->drv_priv, rd);
}
static inline int
hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
hapd->driver->set_country == NULL)
return 0;
return hapd->driver->set_country(hapd->drv_priv, country);
}
static inline int
hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL ||
hapd->driver->set_ieee80211d == NULL)
return 0;
return hapd->driver->set_ieee80211d(hapd->drv_priv, enabled);
}
static inline 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 inline int
hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
u8 *head, size_t head_len,
u8 *tail, size_t tail_len)
{
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
return 0;
return hapd->driver->set_beacon(ifname, hapd->drv_priv, head, head_len,
tail, tail_len);
}
static inline int
hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
return 0;
return hapd->driver->set_internal_bridge(hapd->drv_priv, value);
}
static inline int
hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
return 0;
return hapd->driver->set_beacon_int(hapd->drv_priv, value);
}
static inline int
hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
return 0;
return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->drv_priv,
value);
}
static inline int
hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
return 0;
return hapd->driver->set_broadcast_ssid(hapd->drv_priv, value);
}
static inline 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);
}
static inline int
hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL ||
hapd->driver->set_key_tx_rx_threshold == NULL)
return 0;
return hapd->driver->set_key_tx_rx_threshold(hapd->drv_priv, value);
}
static inline 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);
}
static inline 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);
}
static inline int
hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
return 0;
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
cw_min, cw_max, burst_time);
}
static inline int
hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
{
if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
return 0;
return hapd->driver->bss_add(hapd->drv_priv, ifname, bssid);
}
static inline int
hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
{
if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
return 0;
return hapd->driver->bss_remove(hapd->drv_priv, ifname);
}
static inline 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);
}
static inline int
hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
char *ifname, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->conf->iface, hapd->drv_priv, type,
ifname, addr);
}
static inline int
hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
char *ifname, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->if_update == NULL)
return -1;
return hapd->driver->if_update(hapd->drv_priv, type, ifname, addr);
}
static inline int
hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
char *ifname, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
return -1;
return hapd->driver->if_remove(hapd->drv_priv, type, ifname, addr);
}
static inline int
hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
int interval, int _listen, int *channel,
int *last_rx)
{
if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
return -1;
return hapd->driver->passive_scan(hapd->drv_priv, now, our_mode_only,
interval, _listen, channel, last_rx);
}
static inline struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags)
{
if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
return NULL;
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
flags);
}
static inline int
hostapd_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_driver_commit(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->commit == NULL)
return 0;
return hapd->driver->commit(hapd->drv_priv);
}
static inline 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 inline 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);
}
#ifdef CONFIG_IEEE80211N
static inline int
hostapd_set_ht_params(const char *ifname, 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(
ifname, hapd->drv_priv, ht_capab, ht_capab_len,
ht_oper, ht_oper_len);
}
#endif /* CONFIG_IEEE80211N */
static inline int
hostapd_drv_none(struct hostapd_data *hapd)
{
return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
}
static inline int
hostapd_set_wps_beacon_ie(struct hostapd_data *hapd, const u8 *ie, size_t len)
{
if (hapd->driver == NULL || hapd->driver->set_wps_beacon_ie == NULL)
return 0;
return hapd->driver->set_wps_beacon_ie(hapd->conf->iface,
hapd->drv_priv, ie, len);
}
static inline int
hostapd_set_wps_probe_resp_ie(struct hostapd_data *hapd, const u8 *ie,
size_t len)
{
if (hapd->driver == NULL ||
hapd->driver->set_wps_probe_resp_ie == NULL)
return 0;
return hapd->driver->set_wps_probe_resp_ie(hapd->conf->iface,
hapd->drv_priv, ie, len);
}
#endif /* DRIVER_H */

838
hostapd/driver_bsd.c Normal file
View File

@ -0,0 +1,838 @@
/*
* hostapd / Driver interaction with BSD net80211 layer
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
* Copyright (c) 2004, 2Wire, 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.
*/
#include "includes.h"
#include <sys/ioctl.h>
#include <net/if.h>
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
/*
* Avoid conflicts with hostapd definitions by undefining couple of defines
* from net80211 header files.
*/
#undef RSN_VERSION
#undef WPA_VERSION
#undef WPA_OUI_TYPE
#include "hostapd.h"
#include "driver.h"
#include "ieee802_1x.h"
#include "eloop.h"
#include "sta_info.h"
#include "l2_packet/l2_packet.h"
#include "eapol_sm.h"
#include "wpa.h"
#include "radius/radius.h"
#include "ieee802_11.h"
#include "common.h"
struct bsd_driver_data {
struct hostapd_data *hapd; /* back pointer */
char iface[IFNAMSIZ + 1];
struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
int ioctl_sock; /* socket for ioctl() use */
int wext_sock; /* socket for wireless events */
};
static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code);
static int
set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
ireq.i_type = op;
ireq.i_len = arg_len;
ireq.i_data = (void *) arg;
if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
perror("ioctl[SIOCS80211]");
return -1;
}
return 0;
}
static int
get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
ireq.i_type = op;
ireq.i_len = arg_len;
ireq.i_data = arg;
if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) {
perror("ioctl[SIOCG80211]");
return -1;
}
return ireq.i_len;
}
static int
set80211param(struct bsd_driver_data *drv, int op, int arg)
{
struct ieee80211req ireq;
memset(&ireq, 0, sizeof(ireq));
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
ireq.i_type = op;
ireq.i_val = arg;
if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
perror("ioctl[SIOCS80211]");
return -1;
}
return 0;
}
static const char *
ether_sprintf(const u8 *addr)
{
static char buf[sizeof(MACSTR)];
if (addr != NULL)
snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
else
snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
return buf;
}
/*
* Configure WPA parameters.
*/
static int
bsd_configure_wpa(struct bsd_driver_data *drv)
{
static const char *ciphernames[] =
{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
struct hostapd_data *hapd = drv->hapd;
struct hostapd_bss_config *conf = hapd->conf;
int v;
switch (conf->wpa_group) {
case WPA_CIPHER_CCMP:
v = IEEE80211_CIPHER_AES_CCM;
break;
case WPA_CIPHER_TKIP:
v = IEEE80211_CIPHER_TKIP;
break;
case WPA_CIPHER_WEP104:
v = IEEE80211_CIPHER_WEP;
break;
case WPA_CIPHER_WEP40:
v = IEEE80211_CIPHER_WEP;
break;
case WPA_CIPHER_NONE:
v = IEEE80211_CIPHER_NONE;
break;
default:
printf("Unknown group key cipher %u\n",
conf->wpa_group);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
__func__, ciphernames[v], v);
if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) {
printf("Unable to set group key cipher to %u (%s)\n",
v, ciphernames[v]);
return -1;
}
if (v == IEEE80211_CIPHER_WEP) {
/* key length is done only for specific ciphers */
v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) {
printf("Unable to set group key length to %u\n", v);
return -1;
}
}
v = 0;
if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
v |= 1<<IEEE80211_CIPHER_AES_CCM;
if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
v |= 1<<IEEE80211_CIPHER_TKIP;
if (conf->wpa_pairwise & WPA_CIPHER_NONE)
v |= 1<<IEEE80211_CIPHER_NONE;
wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_IOC_UCASTCIPHERS, v)) {
printf("Unable to set pairwise key ciphers to 0x%x\n", v);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
__func__, conf->wpa_key_mgmt);
if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) {
printf("Unable to set key management algorithms to 0x%x\n",
conf->wpa_key_mgmt);
return -1;
}
v = 0;
if (conf->rsn_preauth)
v |= BIT(0);
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
__func__, conf->rsn_preauth);
if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) {
printf("Unable to set RSN capabilities to 0x%x\n", v);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa);
if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) {
printf("Unable to set WPA to %u\n", conf->wpa);
return -1;
}
return 0;
}
static int
bsd_set_iface_flags(void *priv, int dev_up)
{
struct bsd_driver_data *drv = priv;
struct ifreq ifr;
wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
if (drv->ioctl_sock < 0)
return -1;
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
perror("ioctl[SIOCGIFFLAGS]");
return -1;
}
if (dev_up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
perror("ioctl[SIOCSIFFLAGS]");
return -1;
}
if (dev_up) {
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
ifr.ifr_mtu = HOSTAPD_MTU;
if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
perror("ioctl[SIOCSIFMTU]");
printf("Setting MTU failed - trying to survive with "
"current value\n");
}
}
return 0;
}
static int
bsd_set_ieee8021x(const char *ifname, void *priv, int enabled)
{
struct bsd_driver_data *drv = priv;
struct hostapd_data *hapd = drv->hapd;
struct hostapd_bss_config *conf = hapd->conf;
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
if (!enabled) {
/* XXX restore state */
return set80211param(priv, IEEE80211_IOC_AUTHMODE,
IEEE80211_AUTH_AUTO);
}
if (!conf->wpa && !conf->ieee802_1x) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
return -1;
}
if (conf->wpa && bsd_configure_wpa(drv) != 0) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
return -1;
}
if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
(conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
return -1;
}
return bsd_set_iface_flags(priv, 1);
}
static int
bsd_set_privacy(const char *ifname, void *priv, int enabled)
{
struct bsd_driver_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled);
}
static int
bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
__func__, ether_sprintf(addr), authorized);
if (authorized)
mlme.im_op = IEEE80211_MLME_AUTHORIZE;
else
mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
mlme.im_reason = 0;
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
}
static int
bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or,
int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WLAN_STA_AUTHORIZED)
return bsd_set_sta_authorized(priv, addr, 1);
if (!(flags_and & WLAN_STA_AUTHORIZED))
return bsd_set_sta_authorized(priv, addr, 0);
return 0;
}
static int
bsd_del_key(void *priv, const u8 *addr, int key_idx)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_del_key wk;
wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
__func__, ether_sprintf(addr), key_idx);
memset(&wk, 0, sizeof(wk));
if (addr != NULL) {
memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */
} else {
wk.idk_keyix = key_idx;
}
return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
}
static int
bsd_set_key(const char *ifname, void *priv, const char *alg,
const u8 *addr, int key_idx,
const u8 *key, size_t key_len, int txkey)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_key wk;
u_int8_t cipher;
if (strcmp(alg, "none") == 0)
return bsd_del_key(drv, addr, key_idx);
wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
__func__, alg, ether_sprintf(addr), key_idx);
if (strcmp(alg, "WEP") == 0)
cipher = IEEE80211_CIPHER_WEP;
else if (strcmp(alg, "TKIP") == 0)
cipher = IEEE80211_CIPHER_TKIP;
else if (strcmp(alg, "CCMP") == 0)
cipher = IEEE80211_CIPHER_AES_CCM;
else {
printf("%s: unknown/unsupported algorithm %s\n",
__func__, alg);
return -1;
}
if (key_len > sizeof(wk.ik_keydata)) {
printf("%s: key length %d too big\n", __func__, key_len);
return -3;
}
memset(&wk, 0, sizeof(wk));
wk.ik_type = cipher;
wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
if (addr == NULL) {
memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
wk.ik_keyix = key_idx;
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
} else {
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
wk.ik_keyix = IEEE80211_KEYIX_NONE;
}
wk.ik_keylen = key_len;
memcpy(wk.ik_keydata, key, key_len);
return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
}
static int
bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
u8 *seq)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_key wk;
wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
__func__, ether_sprintf(addr), idx);
memset(&wk, 0, sizeof(wk));
if (addr == NULL)
memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
else
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
wk.ik_keyix = idx;
if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
printf("Failed to get encryption.\n");
return -1;
}
#ifdef WORDS_BIGENDIAN
{
/*
* wk.ik_keytsc is in host byte order (big endian), need to
* swap it to match with the byte order used in WPA.
*/
int i;
u8 tmp[WPA_KEY_RSC_LEN];
memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
}
}
#else /* WORDS_BIGENDIAN */
memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
#endif /* WORDS_BIGENDIAN */
return 0;
}
static int
bsd_flush(void *priv)
{
u8 allsta[IEEE80211_ADDR_LEN];
memset(allsta, 0xff, IEEE80211_ADDR_LEN);
return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
}
static int
bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
const u8 *addr)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_sta_stats stats;
memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) {
/* XXX? do packets counts include non-data frames? */
data->rx_packets = stats.is_stats.ns_rx_data;
data->rx_bytes = stats.is_stats.ns_rx_bytes;
data->tx_packets = stats.is_stats.ns_tx_data;
data->tx_bytes = stats.is_stats.ns_tx_bytes;
}
return 0;
}
static int
bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
{
/*
* Do nothing; we setup parameters at startup that define the
* contents of the beacon information element.
*/
return 0;
}
static int
bsd_sta_deauth(void *priv, const u8 *addr, int reason_code)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
__func__, ether_sprintf(addr), reason_code);
mlme.im_op = IEEE80211_MLME_DEAUTH;
mlme.im_reason = reason_code;
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
}
static int
bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code)
{
struct bsd_driver_data *drv = priv;
struct ieee80211req_mlme mlme;
wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
__func__, ether_sprintf(addr), reason_code);
mlme.im_op = IEEE80211_MLME_DISASSOC;
mlme.im_reason = reason_code;
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
}
static int
bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
{
struct hostapd_data *hapd = drv->hapd;
struct hostapd_bss_config *conf = hapd->conf;
struct sta_info *sta;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deassociated");
sta = ap_get_sta(hapd, addr);
if (sta != NULL) {
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
if (conf->wpa)
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
ap_free_sta(hapd, sta);
}
return 0;
}
static int
bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
{
struct hostapd_data *hapd = drv->hapd;
struct hostapd_bss_config *conf = hapd->conf;
struct sta_info *sta;
struct ieee80211req_wpaie ie;
int new_assoc, ielen, res;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "associated");
sta = ap_sta_add(hapd, addr);
if (sta == NULL)
return -1;
/*
* Fetch and validate any negotiated WPA/RSN parameters.
*/
if (conf->wpa) {
memset(&ie, 0, sizeof(ie));
memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
printf("Failed to get WPA/RSN information element.\n");
return -1; /* XXX not right */
}
ielen = ie.wpa_ie[1];
if (ielen == 0) {
printf("No WPA/RSN information element for station!\n");
return -1; /* XXX not right */
}
ielen += 2;
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr);
if (sta->wpa_sm == NULL) {
printf("Failed to initialize WPA state machine\n");
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
ie.wpa_ie, ielen, NULL, 0);
if (res != WPA_IE_OK) {
printf("WPA/RSN information element rejected? "
"(res %u)\n", res);
return -1;
}
}
/*
* Now that the internal station state is setup
* kick the authenticator into action.
*/
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
return 0;
}
#include <net/route.h>
#include <net80211/ieee80211_freebsd.h>
static void
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
struct bsd_driver_data *drv = ctx;
struct hostapd_data *hapd = drv->hapd;
char buf[2048];
struct if_announcemsghdr *ifan;
struct rt_msghdr *rtm;
struct ieee80211_michael_event *mic;
struct ieee80211_join_event *join;
struct ieee80211_leave_event *leave;
int n;
n = read(sock, buf, sizeof(buf));
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
perror("read(PF_ROUTE)");
return;
}
rtm = (struct rt_msghdr *) buf;
if (rtm->rtm_version != RTM_VERSION) {
wpa_printf(MSG_DEBUG, "Routing message version %d not "
"understood\n", rtm->rtm_version);
return;
}
ifan = (struct if_announcemsghdr *) rtm;
switch (rtm->rtm_type) {
case RTM_IEEE80211:
switch (ifan->ifan_what) {
case RTM_IEEE80211_ASSOC:
case RTM_IEEE80211_REASSOC:
case RTM_IEEE80211_DISASSOC:
case RTM_IEEE80211_SCAN:
break;
case RTM_IEEE80211_LEAVE:
leave = (struct ieee80211_leave_event *) &ifan[1];
bsd_del_sta(drv, leave->iev_addr);
break;
case RTM_IEEE80211_JOIN:
#ifdef RTM_IEEE80211_REJOIN
case RTM_IEEE80211_REJOIN:
#endif
join = (struct ieee80211_join_event *) &ifan[1];
bsd_new_sta(drv, join->iev_addr);
break;
case RTM_IEEE80211_REPLAY:
/* ignore */
break;
case RTM_IEEE80211_MICHAEL:
mic = (struct ieee80211_michael_event *) &ifan[1];
wpa_printf(MSG_DEBUG,
"Michael MIC failure wireless event: "
"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
MAC2STR(mic->iev_src));
ieee80211_michael_mic_failure(hapd, mic->iev_src, 1);
break;
}
break;
}
}
static int
bsd_wireless_event_init(void *priv)
{
struct bsd_driver_data *drv = priv;
int s;
drv->wext_sock = -1;
s = socket(PF_ROUTE, SOCK_RAW, 0);
if (s < 0) {
perror("socket(PF_ROUTE,SOCK_RAW)");
return -1;
}
eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL);
drv->wext_sock = s;
return 0;
}
static void
bsd_wireless_event_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
if (drv != NULL) {
if (drv->wext_sock < 0)
return;
eloop_unregister_read_sock(drv->wext_sock);
close(drv->wext_sock);
}
}
static int
bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
int encrypt, const u8 *own_addr)
{
struct bsd_driver_data *drv = priv;
unsigned char buf[3000];
unsigned char *bp = buf;
struct l2_ethhdr *eth;
size_t len;
int status;
/*
* Prepend the Etherent header. If the caller left us
* space at the front we could just insert it but since
* we don't know we copy to a local buffer. Given the frequency
* and size of frames this probably doesn't matter.
*/
len = data_len + sizeof(struct l2_ethhdr);
if (len > sizeof(buf)) {
bp = malloc(len);
if (bp == NULL) {
printf("EAPOL frame discarded, cannot malloc temp "
"buffer of size %u!\n", len);
return -1;
}
}
eth = (struct l2_ethhdr *) bp;
memcpy(eth->h_dest, addr, ETH_ALEN);
memcpy(eth->h_source, own_addr, ETH_ALEN);
eth->h_proto = htons(ETH_P_EAPOL);
memcpy(eth+1, data, data_len);
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
if (bp != buf)
free(bp);
return status;
}
static void
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
{
struct bsd_driver_data *drv = ctx;
struct hostapd_data *hapd = drv->hapd;
struct sta_info *sta;
sta = ap_get_sta(hapd, src_addr);
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
printf("Data frame from not associated STA %s\n",
ether_sprintf(src_addr));
/* XXX cannot happen */
return;
}
ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
len - sizeof(struct l2_ethhdr));
}
static int
bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
{
struct bsd_driver_data *drv = priv;
int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len);
wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf);
return ssid_len;
}
static int
bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
{
struct bsd_driver_data *drv = priv;
wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf);
return set80211var(drv, IEEE80211_IOC_SSID, buf, len);
}
static void *
bsd_init(struct hostapd_data *hapd)
{
struct bsd_driver_data *drv;
drv = os_zalloc(sizeof(struct bsd_driver_data));
if (drv == NULL) {
printf("Could not allocate memory for bsd driver data\n");
goto bad;
}
drv->hapd = hapd;
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket[PF_INET,SOCK_DGRAM]");
goto bad;
}
memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
handle_read, drv, 1);
if (drv->sock_xmit == NULL)
goto bad;
if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
goto bad;
bsd_set_iface_flags(drv, 0); /* mark down during setup */
return drv;
bad:
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
if (drv != NULL)
free(drv);
return NULL;
}
static void
bsd_deinit(void *priv)
{
struct bsd_driver_data *drv = priv;
(void) bsd_set_iface_flags(drv, 0);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
free(drv);
}
const struct wpa_driver_ops wpa_driver_bsd_ops = {
.name = "bsd",
.init = bsd_init,
.deinit = bsd_deinit,
.set_ieee8021x = bsd_set_ieee8021x,
.set_privacy = bsd_set_privacy,
.set_encryption = bsd_set_key,
.get_seqnum = bsd_get_seqnum,
.flush = bsd_flush,
.set_generic_elem = bsd_set_opt_ie,
.wireless_event_init = bsd_wireless_event_init,
.wireless_event_deinit = bsd_wireless_event_deinit,
.sta_set_flags = bsd_sta_set_flags,
.read_sta_data = bsd_read_sta_driver_data,
.send_eapol = bsd_send_eapol,
.sta_disassoc = bsd_sta_disassoc,
.sta_deauth = bsd_sta_deauth,
.set_ssid = bsd_set_ssid,
.get_ssid = bsd_get_ssid,
};

1279
hostapd/driver_hostap.c Normal file

File diff suppressed because it is too large Load Diff

1483
hostapd/driver_madwifi.c Normal file

File diff suppressed because it is too large Load Diff

2696
hostapd/driver_nl80211.c Normal file

File diff suppressed because it is too large Load Diff

62
hostapd/driver_none.c Normal file
View File

@ -0,0 +1,62 @@
/*
* hostapd / Driver interface for RADIUS server only (no driver)
* Copyright (c) 2008, Atheros Communications
*
* 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "driver.h"
struct none_driver_data {
struct hostapd_data *hapd;
};
static void * none_driver_init(struct hostapd_data *hapd)
{
struct none_driver_data *drv;
drv = os_zalloc(sizeof(struct none_driver_data));
if (drv == NULL) {
wpa_printf(MSG_ERROR, "Could not allocate memory for none "
"driver data");
return NULL;
}
drv->hapd = hapd;
return drv;
}
static void none_driver_deinit(void *priv)
{
struct none_driver_data *drv = priv;
os_free(drv);
}
static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
u16 proto, const u8 *data, size_t data_len)
{
return 0;
}
const struct wpa_driver_ops wpa_driver_none_ops = {
.name = "none",
.init = none_driver_init,
.deinit = none_driver_deinit,
.send_ether = none_driver_send_ether,
};

1091
hostapd/driver_prism54.c Normal file

File diff suppressed because it is too large Load Diff

1300
hostapd/driver_test.c Normal file

File diff suppressed because it is too large Load Diff

372
hostapd/driver_wired.c Normal file
View File

@ -0,0 +1,372 @@
/*
* hostapd / Kernel driver communication for wired (Ethernet) drivers
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
*
* 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.
*/
#include "includes.h"
#include <sys/ioctl.h>
#ifdef USE_KERNEL_HEADERS
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#include <linux/if_arp.h>
#include <linux/if.h>
#else /* USE_KERNEL_HEADERS */
#include <net/if_arp.h>
#include <net/if.h>
#include <netpacket/packet.h>
#endif /* USE_KERNEL_HEADERS */
#include "hostapd.h"
#include "ieee802_1x.h"
#include "eloop.h"
#include "sta_info.h"
#include "driver.h"
#include "accounting.h"
struct wired_driver_data {
struct hostapd_data *hapd;
int sock; /* raw packet socket for driver access */
int dhcp_sock; /* socket for dhcp packets */
int use_pae_group_addr;
};
#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03}
/* TODO: detecting new devices should eventually be changed from using DHCP
* snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
* based on ebtables, etc. */
struct dhcp_message {
u_int8_t op;
u_int8_t htype;
u_int8_t hlen;
u_int8_t hops;
u_int32_t xid;
u_int16_t secs;
u_int16_t flags;
u_int32_t ciaddr;
u_int32_t yiaddr;
u_int32_t siaddr;
u_int32_t giaddr;
u_int8_t chaddr[16];
u_int8_t sname[64];
u_int8_t file[128];
u_int32_t cookie;
u_int8_t options[308]; /* 312 - cookie */
};
static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
{
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
if (sta)
return;
wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
" - adding a new STA", MAC2STR(addr));
sta = ap_sta_add(hapd, addr);
if (sta) {
hostapd_new_assoc_sta(hapd, sta, 0);
} else {
wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
MAC2STR(addr));
}
}
static void handle_data(struct hostapd_data *hapd, unsigned char *buf,
size_t len)
{
struct ieee8023_hdr *hdr;
u8 *pos, *sa;
size_t left;
/* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
* 2 byte ethertype */
if (len < 14) {
wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
(unsigned long) len);
return;
}
hdr = (struct ieee8023_hdr *) buf;
switch (ntohs(hdr->ethertype)) {
case ETH_P_PAE:
wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
sa = hdr->src;
wired_possible_new_sta(hapd, sa);
pos = (u8 *) (hdr + 1);
left = len - sizeof(*hdr);
ieee802_1x_receive(hapd, sa, pos, left);
break;
default:
wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
ntohs(hdr->ethertype));
break;
}
}
static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
{
struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
int len;
unsigned char buf[3000];
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
perror("recv");
return;
}
handle_data(hapd, buf, len);
}
static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
{
struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
int len;
unsigned char buf[3000];
struct dhcp_message *msg;
u8 *mac_address;
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
perror("recv");
return;
}
/* must contain at least dhcp_message->chaddr */
if (len < 44) {
wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
return;
}
msg = (struct dhcp_message *) buf;
mac_address = (u8 *) &(msg->chaddr);
wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
MAC2STR(mac_address));
wired_possible_new_sta(hapd, mac_address);
}
static int wired_init_sockets(struct wired_driver_data *drv)
{
struct hostapd_data *hapd = drv->hapd;
struct ifreq ifr;
struct sockaddr_ll addr;
struct sockaddr_in addr2;
struct packet_mreq mreq;
u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP;
int n = 1;
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
if (drv->sock < 0) {
perror("socket[PF_PACKET,SOCK_RAW]");
return -1;
}
if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) {
printf("Could not register read socket\n");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
perror("ioctl(SIOCGIFINDEX)");
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifr.ifr_ifindex;
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind");
return -1;
}
/* filter multicast address */
memset(&mreq, 0, sizeof(mreq));
mreq.mr_ifindex = ifr.ifr_ifindex;
mreq.mr_type = PACKET_MR_MULTICAST;
mreq.mr_alen = 6;
memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen);
if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFHWADDR)");
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
printf("Invalid HW-addr family 0x%04x\n",
ifr.ifr_hwaddr.sa_family);
return -1;
}
memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
/* setup dhcp listen socket for sta detection */
if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket call failed for dhcp");
return -1;
}
if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL))
{
printf("Could not register read socket\n");
return -1;
}
memset(&addr2, 0, sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_port = htons(67);
addr2.sin_addr.s_addr = INADDR_ANY;
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
sizeof(n)) == -1) {
perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
return -1;
}
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
sizeof(n)) == -1) {
perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
return -1;
}
if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
sizeof(struct sockaddr)) == -1) {
perror("bind");
return -1;
}
return 0;
}
static int wired_send_eapol(void *priv, const u8 *addr,
const u8 *data, size_t data_len, int encrypt,
const u8 *own_addr)
{
struct wired_driver_data *drv = priv;
u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP;
struct ieee8023_hdr *hdr;
size_t len;
u8 *pos;
int res;
len = sizeof(*hdr) + data_len;
hdr = os_zalloc(len);
if (hdr == NULL) {
printf("malloc() failed for wired_send_eapol(len=%lu)\n",
(unsigned long) len);
return -1;
}
memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
ETH_ALEN);
memcpy(hdr->src, own_addr, ETH_ALEN);
hdr->ethertype = htons(ETH_P_PAE);
pos = (u8 *) (hdr + 1);
memcpy(pos, data, data_len);
res = send(drv->sock, (u8 *) hdr, len, 0);
free(hdr);
if (res < 0) {
perror("wired_send_eapol: send");
printf("wired_send_eapol - packet len: %lu - failed\n",
(unsigned long) len);
}
return res;
}
static void * wired_driver_init(struct hostapd_data *hapd)
{
struct wired_driver_data *drv;
drv = os_zalloc(sizeof(struct wired_driver_data));
if (drv == NULL) {
printf("Could not allocate memory for wired driver data\n");
return NULL;
}
drv->hapd = hapd;
drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
if (wired_init_sockets(drv)) {
free(drv);
return NULL;
}
return drv;
}
static void wired_driver_deinit(void *priv)
{
struct wired_driver_data *drv = priv;
if (drv->sock >= 0)
close(drv->sock);
if (drv->dhcp_sock >= 0)
close(drv->dhcp_sock);
free(drv);
}
const struct wpa_driver_ops wpa_driver_wired_ops = {
.name = "wired",
.init = wired_driver_init,
.deinit = wired_driver_deinit,
.send_eapol = wired_send_eapol,
};

71
hostapd/drivers.c Normal file
View File

@ -0,0 +1,71 @@
/*
* hostapd / driver interface list
* Copyright (c) 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.
*/
#include "includes.h"
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
#ifdef CONFIG_DRIVER_NL80211
extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_PRISM54
extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
#endif /* CONFIG_DRIVER_PRISM54 */
#ifdef CONFIG_DRIVER_MADWIFI
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
#ifdef CONFIG_DRIVER_WIRED
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_NONE
extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
#endif /* CONFIG_DRIVER_NONE */
struct wpa_driver_ops *hostapd_drivers[] =
{
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_PRISM54
&wpa_driver_prism54_ops,
#endif /* CONFIG_DRIVER_PRISM54 */
#ifdef CONFIG_DRIVER_MADWIFI
&wpa_driver_madwifi_ops,
#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
&wpa_driver_test_ops,
#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_NONE
&wpa_driver_none_ops,
#endif /* CONFIG_DRIVER_NONE */
NULL
};

77
hostapd/eap_testing.txt Normal file
View File

@ -0,0 +1,77 @@
Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
Test matrix
+) tested successfully
F) failed
-) peer did not support
?) not tested
XSupplicant --------------------------------.
Intel PROSet ---------------------------. |
Windows XP -------------------------. | |
Mac OS X 10.4 ------------------. | | |
Nokia S60 ------------------. | | | |
wpa_supplicant ---------. | | | | |
| | | | | |
EAP-MD5 + - ? ? -
EAP-GTC + - ? - -
EAP-MSCHAPv2 + - ? - -
EAP-TLS + + +1 + +
EAP-PEAPv0/MSCHAPv2 + + + + + +
EAP-PEAPv0/GTC + + + - +
EAP-PEAPv0/MD5 + - + - -
EAP-PEAPv0/TLS + F - + +
EAP-PEAPv0/SIM + + - - -
EAP-PEAPv0/AKA + + - - -
EAP-PEAPv0/PSK + - - - -
EAP-PEAPv0/PAX + - - - -
EAP-PEAPv0/SAKE + - - - -
EAP-PEAPv0/GPSK + - - - -
EAP-PEAPv1/MSCHAPv2 + + + - + +
EAP-PEAPv1/GTC + + + - +
EAP-PEAPv1/MD5 + - + - -
EAP-PEAPv1/TLS + F - - +
EAP-PEAPv1/SIM + + - - -
EAP-PEAPv1/AKA + + - - -
EAP-PEAPv1/PSK + - - - -
EAP-PEAPv1/PAX + - - - -
EAP-PEAPv1/SAKE + - - - -
EAP-PEAPv1/GPSK + - - - -
EAP-TTLS/CHAP + - + - + +
EAP-TTLS/MSCHAP + - + - + +
EAP-TTLS/MSCHAPv2 + + + - + +
EAP-TTLS/PAP + - + - + +
EAP-TTLS/EAP-MD5 + - - - - +
EAP-TTLS/EAP-GTC + + - - -
EAP-TTLS/EAP-MSCHAPv2 + + - - -
EAP-TTLS/EAP-TLS + F - - -
EAP-TTLS/EAP-SIM + + - - -
EAP-TTLS/EAP-AKA + + - - -
EAP-TTLS + TNC + - - - -
EAP-SIM + + - - +
EAP-AKA + + - - -
EAP-PAX + - - - -
EAP-SAKE + - - - -
EAP-GPSK + - - - -
EAP-FAST/MSCHAPv2(prov) + - F - F
EAP-FAST/GTC(auth) + - + - +
EAP-FAST/MSCHAPv2(aprov)+ - F - F
EAP-FAST/GTC(aprov) + - F - F
EAP-FAST/MD5(aprov) + - - - -
EAP-FAST/TLS(aprov) + - - - -
EAP-FAST/SIM(aprov) + - - - -
EAP-FAST/AKA(aprov) + - - - -
EAP-FAST/MSCHAPv2(auth) + - + - +
EAP-FAST/MD5(auth) + - + - -
EAP-FAST/TLS(auth) + - - - -
EAP-FAST/SIM(auth) + - - - -
EAP-FAST/AKA(auth) + - - - -
EAP-FAST + TNC + - - - -
EAP-IKEv2 + - - - -
EAP-TNC + - - - -
1) EAP-TLS itself worked, but peer certificate validation failed at
least when using the internal TLS server (peer included incorrect
certificates in the chain?)

1342
hostapd/eapol_sm.c Normal file

File diff suppressed because it is too large Load Diff

260
hostapd/eapol_sm.h Normal file
View File

@ -0,0 +1,260 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine
* 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.
*/
#ifndef EAPOL_SM_H
#define EAPOL_SM_H
#include "defs.h"
/* IEEE Std 802.1X-2004, Ch. 8.2 */
typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
PortTypes;
typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
typedef enum { Both = 0, In = 1 } ControlledDirection;
typedef unsigned int Counter;
struct eap_sm;
struct radius_attr_data {
u8 *data;
size_t len;
};
struct radius_class_data {
struct radius_attr_data *attr;
size_t count;
};
struct eapol_auth_config {
int eap_reauth_period;
int wpa;
int individual_wep_key_len;
int eap_server;
void *ssl_ctx;
void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
char *eap_fast_a_id_info;
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
int eap_sim_aka_result_ind;
int tnc;
struct wps_context *wps;
/*
* Pointer to hostapd data. This is a temporary workaround for
* transition phase and will be removed once IEEE 802.1X/EAPOL code is
* separated more cleanly from rest of hostapd.
*/
struct hostapd_data *hapd;
};
struct eap_user;
typedef enum {
EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
} eapol_logger_level;
struct eapol_auth_cb {
void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data,
size_t datalen);
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
size_t datalen);
void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
int (*sta_entry_alive)(void *ctx, const u8 *addr);
void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level,
const char *txt);
void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized);
void (*abort_auth)(void *ctx, void *sta_ctx);
void (*tx_key)(void *ctx, void *sta_ctx);
};
/**
* struct eapol_authenticator - Global EAPOL authenticator data
*/
struct eapol_authenticator {
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
};
/**
* struct eapol_state_machine - Per-Supplicant Authenticator state machines
*/
struct eapol_state_machine {
/* timers */
int aWhile;
int quietWhile;
int reAuthWhen;
/* global variables */
Boolean authAbort;
Boolean authFail;
PortState authPortStatus;
Boolean authStart;
Boolean authTimeout;
Boolean authSuccess;
Boolean eapolEap;
Boolean initialize;
Boolean keyDone;
Boolean keyRun;
Boolean keyTxEnabled;
PortTypes portControl;
Boolean portValid;
Boolean reAuthenticate;
/* Port Timers state machine */
/* 'Boolean tick' implicitly handled as registered timeout */
/* Authenticator PAE state machine */
enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
/* variables */
Boolean eapolLogoff;
Boolean eapolStart;
PortTypes portMode;
unsigned int reAuthCount;
/* constants */
unsigned int quietPeriod; /* default 60; 0..65535 */
#define AUTH_PAE_DEFAULT_quietPeriod 60
unsigned int reAuthMax; /* default 2 */
#define AUTH_PAE_DEFAULT_reAuthMax 2
/* counters */
Counter authEntersConnecting;
Counter authEapLogoffsWhileConnecting;
Counter authEntersAuthenticating;
Counter authAuthSuccessesWhileAuthenticating;
Counter authAuthTimeoutsWhileAuthenticating;
Counter authAuthFailWhileAuthenticating;
Counter authAuthEapStartsWhileAuthenticating;
Counter authAuthEapLogoffWhileAuthenticating;
Counter authAuthReauthsWhileAuthenticated;
Counter authAuthEapStartsWhileAuthenticated;
Counter authAuthEapLogoffWhileAuthenticated;
/* Backend Authentication state machine */
enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
BE_AUTH_IGNORE
} be_auth_state;
/* constants */
unsigned int serverTimeout; /* default 30; 1..X */
#define BE_AUTH_DEFAULT_serverTimeout 30
/* counters */
Counter backendResponses;
Counter backendAccessChallenges;
Counter backendOtherRequestsToSupplicant;
Counter backendAuthSuccesses;
Counter backendAuthFails;
/* Reauthentication Timer state machine */
enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
} reauth_timer_state;
/* constants */
unsigned int reAuthPeriod; /* default 3600 s */
Boolean reAuthEnabled;
/* Authenticator Key Transmit state machine */
enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
} auth_key_tx_state;
/* Key Receive state machine */
enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
/* variables */
Boolean rxKey;
/* Controlled Directions state machine */
enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
/* variables */
ControlledDirection adminControlledDirections;
ControlledDirection operControlledDirections;
Boolean operEdge;
/* Authenticator Statistics Table */
Counter dot1xAuthEapolFramesRx;
Counter dot1xAuthEapolFramesTx;
Counter dot1xAuthEapolStartFramesRx;
Counter dot1xAuthEapolLogoffFramesRx;
Counter dot1xAuthEapolRespIdFramesRx;
Counter dot1xAuthEapolRespFramesRx;
Counter dot1xAuthEapolReqIdFramesTx;
Counter dot1xAuthEapolReqFramesTx;
Counter dot1xAuthInvalidEapolFramesRx;
Counter dot1xAuthEapLengthErrorFramesRx;
Counter dot1xAuthLastEapolFrameVersion;
/* Other variables - not defined in IEEE 802.1X */
u8 addr[ETH_ALEN]; /* Supplicant address */
#define EAPOL_SM_PREAUTH BIT(0)
#define EAPOL_SM_WAIT_START BIT(1)
int flags; /* EAPOL_SM_* */
/* EAPOL/AAA <-> EAP full authenticator interface */
struct eap_eapol_interface *eap_if;
int radius_identifier;
/* TODO: check when the last messages can be released */
struct radius_msg *last_recv_radius;
u8 last_eap_id; /* last used EAP Identifier */
u8 *identity;
size_t identity_len;
u8 eap_type_authsrv; /* EAP type of the last EAP packet from
* Authentication server */
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
struct radius_class_data radius_class;
/* Keys for encrypting and signing EAPOL-Key frames */
u8 *eapol_key_sign;
size_t eapol_key_sign_len;
u8 *eapol_key_crypt;
size_t eapol_key_crypt_len;
struct eap_sm *eap;
Boolean initializing; /* in process of initializing state machines */
Boolean changed;
struct eapol_authenticator *eapol;
/* Somewhat nasty pointers to global hostapd and STA data to avoid
* passing these to every function */
struct hostapd_data *hapd;
struct sta_info *sta;
};
struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
struct eapol_auth_cb *cb);
void eapol_auth_deinit(struct eapol_authenticator *eapol);
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
int preauth, struct sta_info *sta);
void eapol_auth_free(struct eapol_state_machine *sm);
void eapol_auth_step(struct eapol_state_machine *sm);
void eapol_auth_initialize(struct eapol_state_machine *sm);
void eapol_auth_dump_state(FILE *f, const char *prefix,
struct eapol_state_machine *sm);
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
#endif /* EAPOL_SM_H */

216
hostapd/hostap_common.h Normal file
View File

@ -0,0 +1,216 @@
/*
* hostapd / Kernel driver communication with Linux Host AP driver
* Copyright (c) 2002-2006, 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.
*/
#ifndef HOSTAP_COMMON_H
#define HOSTAP_COMMON_H
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
/* New wireless extensions API - SET/GET convention (even ioctl numbers are
* root only)
*/
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
/* following are not in SIOCGIWPRIV list; check permission in the driver code
*/
#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
enum {
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
PRISM2_PARAM_TXRATECTRL = 2,
PRISM2_PARAM_BEACON_INT = 3,
PRISM2_PARAM_PSEUDO_IBSS = 4,
PRISM2_PARAM_ALC = 5,
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
PRISM2_PARAM_DUMP = 7,
PRISM2_PARAM_OTHER_AP_POLICY = 8,
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
PRISM2_PARAM_DTIM_PERIOD = 11,
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
PRISM2_PARAM_MAX_WDS = 13,
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
PRISM2_PARAM_AP_AUTH_ALGS = 15,
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
PRISM2_PARAM_HOST_ENCRYPT = 17,
PRISM2_PARAM_HOST_DECRYPT = 18,
PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
PRISM2_PARAM_HOST_ROAMING = 21,
PRISM2_PARAM_BCRX_STA_KEY = 22,
PRISM2_PARAM_IEEE_802_1X = 23,
PRISM2_PARAM_ANTSEL_TX = 24,
PRISM2_PARAM_ANTSEL_RX = 25,
PRISM2_PARAM_MONITOR_TYPE = 26,
PRISM2_PARAM_WDS_TYPE = 27,
PRISM2_PARAM_HOSTSCAN = 28,
PRISM2_PARAM_AP_SCAN = 29,
PRISM2_PARAM_ENH_SEC = 30,
PRISM2_PARAM_IO_DEBUG = 31,
PRISM2_PARAM_BASIC_RATES = 32,
PRISM2_PARAM_OPER_RATES = 33,
PRISM2_PARAM_HOSTAPD = 34,
PRISM2_PARAM_HOSTAPD_STA = 35,
PRISM2_PARAM_WPA = 36,
PRISM2_PARAM_PRIVACY_INVOKED = 37,
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
};
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
AP_MAC_CMD_KICKALL = 4 };
/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
enum {
PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
/* Note! Old versions of prism2_srec have a fatal error in CRC-16
* calculation, which will corrupt all non-volatile downloads.
* PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
* prevent use of old versions of prism2_srec for non-volatile
* download. */
PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
/* Persistent versions of volatile download commands (keep firmware
* data in memory and automatically re-download after hw_reset */
PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
};
struct prism2_download_param {
u32 dl_cmd;
u32 start_addr;
u32 num_areas;
struct prism2_download_area {
u32 addr; /* wlan card address */
u32 len;
caddr_t ptr; /* pointer to data in user space */
} data[0];
};
#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
#define PRISM2_MAX_DOWNLOAD_LEN 262144
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
enum {
PRISM2_HOSTAPD_FLUSH = 1,
PRISM2_HOSTAPD_ADD_STA = 2,
PRISM2_HOSTAPD_REMOVE_STA = 3,
PRISM2_HOSTAPD_GET_INFO_STA = 4,
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
PRISM2_SET_ENCRYPTION = 6,
PRISM2_GET_ENCRYPTION = 7,
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
PRISM2_HOSTAPD_GET_RID = 9,
PRISM2_HOSTAPD_SET_RID = 10,
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
PRISM2_HOSTAPD_MLME = 13,
PRISM2_HOSTAPD_SCAN_REQ = 14,
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
};
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_RID_HDR_LEN \
((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
*/
#define HOSTAP_CRYPT_ALG_NAME_LEN 16
struct prism2_hostapd_param {
u32 cmd;
u8 sta_addr[ETH_ALEN];
union {
struct {
u16 aid;
u16 capability;
u8 tx_supp_rates;
} add_sta;
struct {
u32 inactive_sec;
} get_info_sta;
struct {
u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
u32 flags;
u32 err;
u8 idx;
u8 seq[8]; /* sequence counter (set: RX, get: TX) */
u16 key_len;
u8 key[0];
} crypt;
struct {
u32 flags_and;
u32 flags_or;
} set_flags_sta;
struct {
u16 rid;
u16 len;
u8 data[0];
} rid;
struct {
u8 len;
u8 data[0];
} generic_elem;
struct {
#define MLME_STA_DEAUTH 0
#define MLME_STA_DISASSOC 1
u16 cmd;
u16 reason_code;
} mlme;
struct {
u8 ssid_len;
u8 ssid[32];
} scan_req;
} u;
};
#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
#endif /* HOSTAP_COMMON_H */

59
hostapd/hostapd.8 Normal file
View File

@ -0,0 +1,59 @@
.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd
.SH NAME
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
.SH SYNOPSIS
.B hostapd
[-hdBKtv] [-P <PID file>] <configuration file(s)>
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd
daemon.
.PP
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
The current version supports Linux (Host AP, madwifi, Prism54 drivers) and FreeBSD (net80211).
.B hostapd
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
.B hostapd
supports separate frontend programs and an example text-based frontend,
.BR hostapd_cli ,
is included with
.BR hostapd .
.SH OPTIONS
A summary of options is included below.
For a complete description, run
.BR hostapd
from the command line.
.TP
.B \-h
Show usage.
.TP
.B \-d
Show more debug messages.
.TP
.B \-dd
Show even more debug messages.
.TP
.B \-B
Run daemon in the background.
.TP
.B \-P <PID file>
Path to PID file.
.TP
.B \-K
Include key data in debug messages.
.TP
.B \-t
Include timestamps in some debug messages.
.TP
.B \-v
Show hostapd version.
.SH SEE ALSO
.BR hostapd_cli (1).
.SH AUTHOR
hostapd was written by Jouni Malinen <j@w1.fi>.
.PP
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
for the Debian project (but may be used by others).

6
hostapd/hostapd.accept Normal file
View File

@ -0,0 +1,6 @@
# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
# with the AP. Optional VLAN ID can be assigned for clients based on the
# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used.
00:11:22:33:44:55
00:66:77:88:99:aa
00:00:22:33:44:55 1

2027
hostapd/hostapd.c Normal file

File diff suppressed because it is too large Load Diff

1024
hostapd/hostapd.conf Normal file

File diff suppressed because it is too large Load Diff

5
hostapd/hostapd.deny Normal file
View File

@ -0,0 +1,5 @@
# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
# with the AP.
00:20:30:40:50:60
00:ab:cd:ef:12:34
00:00:30:40:50:60

91
hostapd/hostapd.eap_user Normal file
View File

@ -0,0 +1,91 @@
# hostapd user database for integrated EAP server
# Each line must contain an identity, EAP method(s), and an optional password
# separated with whitespace (space or tab). The identity and password must be
# double quoted ("user"). Password can alternatively be stored as
# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
# that the plaintext password does not need to be included in the user file.
# Password hash is stored as hash:<16-octets of hex data> without quotation
# marks.
# [2] flag in the end of the line can be used to mark users for tunneled phase
# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
# identity can be used in the unencrypted phase 1 and the real user identity
# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
# access is needed, two user entries is needed, one for phase 1 and another
# with the same username for phase 2.
#
# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
# password option.
# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
# password.
# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
#
# * can be used as a wildcard to match any user identity. The main purposes for
# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
# avoid having to configure every certificate for EAP-TLS authentication. The
# first matching entry is selected, so * should be used as the last phase 1
# user entry.
#
# "prefix"* can be used to match the given prefix and anything after this. The
# main purpose for this is to be able to avoid EAP method negotiation when the
# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
# is only allowed for phase 1 identities.
#
# Multiple methods can be configured to make the authenticator try them one by
# one until the peer accepts one. The method names are separated with a
# comma (,).
#
# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
# version based on the Phase 1 identity. Without this flag, the EAP
# authenticator advertises the highest supported version and select the version
# based on the first PEAP packet from the supplicant.
#
# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
# Tunneled EAP methods are configured with standard EAP method name and [2]
# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
# hash.
# Phase 1 users
"user" MD5 "password"
"test user" MD5 "secret"
"example user" TLS
"DOMAIN\user" MSCHAPV2 "password"
"gtc user" GTC "password"
"pax user" PAX "unknown"
"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef
"psk user" PSK "unknown"
"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef
"sake.user@example.com" SAKE 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
"ttls" TTLS
"not anonymous" PEAP
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
"0"* AKA,TTLS,TLS,PEAP,SIM
"1"* SIM,TTLS,TLS,PEAP,AKA
"2"* AKA,TTLS,TLS,PEAP,SIM
"3"* SIM,TTLS,TLS,PEAP,AKA
"4"* AKA,TTLS,TLS,PEAP,SIM
"5"* SIM,TTLS,TLS,PEAP,AKA
# Wildcard for all other identities
* PEAP,TTLS,TLS,SIM,AKA
# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
"t-md5" MD5 "password" [2]
"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2]
"t-gtc" GTC "password" [2]
"not anonymous" MSCHAPV2 "password" [2]
"user" MD5,GTC,MSCHAPV2 "password" [2]
"test user" MSCHAPV2 hash:000102030405060708090a0b0c0d0e0f [2]
"ttls-user" TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2 "password" [2]
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
"0"* AKA [2]
"1"* SIM [2]
"2"* AKA [2]
"3"* SIM [2]
"4"* AKA [2]
"5"* SIM [2]

238
hostapd/hostapd.h Normal file
View File

@ -0,0 +1,238 @@
/*
* hostapd / Initialization and configuration
* Host AP kernel driver
* Copyright (c) 2002-2008, 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.
*/
#ifndef HOSTAPD_H
#define HOSTAPD_H
#include "common.h"
#include "ap.h"
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#endif /* ETH_P_PAE */
#ifndef ETH_P_EAPOL
#define ETH_P_EAPOL ETH_P_PAE
#endif /* ETH_P_EAPOL */
#ifndef ETH_P_RRB
#define ETH_P_RRB 0x890D
#endif /* ETH_P_RRB */
#include "config.h"
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
#define MAX_VLAN_ID 4094
struct ieee8023_hdr {
u8 dest[6];
u8 src[6];
u16 ethertype;
} STRUCT_PACKED;
struct ieee80211_hdr {
le16 frame_control;
le16 duration_id;
u8 addr1[6];
u8 addr2[6];
u8 addr3[6];
le16 seq_ctrl;
/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
*/
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#define IEEE80211_DA_FROMDS addr1
#define IEEE80211_BSSID_FROMDS addr2
#define IEEE80211_SA_FROMDS addr3
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
* frames that might be longer than normal default MTU and they are not
* fragmented */
#define HOSTAPD_MTU 2290
extern unsigned char rfc1042_header[6];
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
unsigned long current_tx_rate;
unsigned long inactive_msec;
unsigned long flags;
unsigned long num_ps_buf_frames;
unsigned long tx_retry_failed;
unsigned long tx_retry_count;
int last_rssi;
int last_ack_rssi;
};
struct wpa_driver_ops;
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
int interface_added; /* virtual interface added for this BSS */
u8 own_addr[ETH_ALEN];
int num_sta; /* number of entries in sta_list */
struct sta_info *sta_list; /* STA info list head */
struct sta_info *sta_hash[STA_HASH_SIZE];
/* pointers to STA info; based on allocated AID or NULL if AID free
* AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
* and so on
*/
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
const struct wpa_driver_ops *driver;
void *drv_priv;
u8 *default_wep_key;
u8 default_wep_key_idx;
struct radius_client_data *radius;
int radius_client_reconfigured;
u32 acct_session_id_hi, acct_session_id_lo;
struct iapp_data *iapp;
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
struct rsn_preauth_interface *preauth_iface;
time_t michael_mic_failure;
int michael_mic_failures;
int tkip_countermeasures;
int ctrl_sock;
struct wpa_ctrl_dst *ctrl_dst;
void *ssl_ctx;
void *eap_sim_db_priv;
struct radius_server_data *radius_srv;
int parameter_set_count;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan *full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct l2_packet_data *l2;
struct wps_context *wps;
#ifdef CONFIG_WPS
u8 *wps_beacon_ie;
size_t wps_beacon_ie_len;
u8 *wps_probe_resp_ie;
size_t wps_probe_resp_ie_len;
unsigned int ap_pin_failures;
struct upnp_wps_device_sm *wps_upnp;
#endif /* CONFIG_WPS */
};
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
struct hostapd_iface {
char *config_fname;
struct hostapd_config *conf;
size_t num_bss;
struct hostapd_data **bss;
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
struct ap_info *ap_iter_list;
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
/* Rates that are currently used (i.e., filtered copy of
* current_mode->channels */
int num_rates;
struct hostapd_rate_data *current_rates;
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
* in 802.11g BSS) */
int num_sta_non_erp;
/* Number of associated stations that do not support Short Slot Time */
int num_sta_no_short_slot_time;
/* Number of associated stations that do not support Short Preamble */
int num_sta_no_short_preamble;
int olbc; /* Overlapping Legacy BSS Condition */
/* Number of HT associated stations that do not support greenfield */
int num_sta_ht_no_gf;
/* Number of associated non-HT stations */
int num_sta_no_ht;
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
/* Overlapping BSS information */
int olbc_ht;
#ifdef CONFIG_IEEE80211N
u16 ht_op_mode;
#endif /* CONFIG_IEEE80211N */
};
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
int hostapd_reload_config(struct hostapd_iface *iface);
#endif /* HOSTAPD_H */

View File

@ -0,0 +1,4 @@
# RADIUS client configuration for the RADIUS server
10.1.2.3 secret passphrase
192.168.1.0/24 another very secret passphrase
0.0.0.0/0 radius

9
hostapd/hostapd.sim_db Normal file
View File

@ -0,0 +1,9 @@
# Example GSM authentication triplet file for EAP-SIM authenticator
# IMSI:Kc:SRES:RAND
# IMSI: ASCII string (numbers)
# Kc: hex, 8 octets
# SRES: hex, 4 octets
# RAND: hex, 16 octets
234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

9
hostapd/hostapd.vlan Normal file
View File

@ -0,0 +1,9 @@
# VLAN ID to network interface mapping
1 vlan1
2 vlan2
3 vlan3
100 guest
# Optional wildcard entry matching all VLAN IDs. The first # in the interface
# name will be replaced with the VLAN ID. The network interfaces are created
# (and removed) dynamically based on the use.
* vlan#

9
hostapd/hostapd.wpa_psk Normal file
View File

@ -0,0 +1,9 @@
# List of WPA PSKs. Each line, except for empty lines and lines starting
# with #, must contain a MAC address and PSK separated with a space.
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
# characters or as a 256-bit hex PSK (64 hex digits).
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
00:00:00:00:00:00 another passphrase for all STAs

83
hostapd/hostapd_cli.1 Normal file
View File

@ -0,0 +1,83 @@
.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface"
.SH NAME
hostapd_cli \- hostapd command-line interface
.SH SYNOPSIS
.B hostapd_cli
[-p<path>] [-i<ifname>] [-hv] [command..]
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd_cli
utility.
.PP
.B hostapd_cli
is a command-line interface for the
.B hostapd
daemon.
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
For more information about
.B hostapd
refer to the
.BR hostapd (8)
man page.
.SH OPTIONS
A summary of options is included below.
For a complete description, run
.BR hostapd_cli
from the command line.
.TP
.B \-p<path>
Path to find control sockets.
Default: /var/run/hostapd
.TP
.B \-i<ifname>
Interface to listen on.
Default: first interface found in socket path.
.TP
.B \-h
Show usage.
.TP
.B \-v
Show hostapd_cli version.
.SH COMMANDS
A summary of commands is included below.
For a complete description, run
.BR hostapd_cli
from the command line.
.TP
.B mib
Get MIB variables (dot1x, dot11, radius).
.TP
.B sta <addr>
Get MIB variables for one station.
.TP
.B all_sta
Get MIB variables for all stations.
.TP
.B help
Get usage help.
.TP
.B interface [ifname]
Show interfaces/select interface.
.TP
.B level <debug level>
Change debug level.
.TP
.B license
Show full
.B hostapd_cli
license.
.TP
.B quit
Exit hostapd_cli.
.SH SEE ALSO
.BR hostapd (8).
.SH AUTHOR
hostapd_cli was written by Jouni Malinen <j@w1.fi>.
.PP
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
for the Debian project (but may be used by others).

673
hostapd/hostapd_cli.c Normal file
View File

@ -0,0 +1,673 @@
/*
* hostapd - command line interface for hostapd daemon
* 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.
*/
#include "includes.h"
#include <dirent.h>
#include "wpa_ctrl.h"
#include "common.h"
#include "version.h"
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
"Copyright (c) 2004-2009, 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";
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"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions are\n"
"met:\n"
"\n"
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n"
"\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in the\n"
" documentation and/or other materials provided with the distribution.\n"
"\n"
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
" names of its contributors may be used to endorse or promote products\n"
" derived from this software without specific prior written permission.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
static const char *commands_help =
"Commands:\n"
" mib get MIB variables (dot1x, dot11, radius)\n"
" sta <addr> get MIB variables for one station\n"
" all_sta get MIB variables for all stations\n"
" new_sta <addr> add a new station\n"
#ifdef CONFIG_IEEE80211W
" sa_query <addr> send SA Query to a station\n"
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
" wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n"
" wps_pbc indicate button pushed to initiate PBC\n"
#endif /* CONFIG_WPS */
" help show this usage help\n"
" interface [ifname] show interfaces/select interface\n"
" level <debug level> change debug level\n"
" license show full hostapd_cli license\n"
" quit exit hostapd_cli\n";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
static int hostapd_cli_attached = 0;
static const char *ctrl_iface_dir = "/var/run/hostapd";
static char *ctrl_ifname = NULL;
static int ping_interval = 5;
static void usage(void)
{
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
"[-G<ping interval>] \\\n"
" [command..]\n"
"\n"
"Options:\n"
" -h help (show this usage text)\n"
" -v shown version information\n"
" -p<path> path to find control sockets (default: "
"/var/run/hostapd)\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
" socket path)\n\n"
"%s",
commands_help);
}
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
{
char *cfile;
int flen;
if (ifname == NULL)
return NULL;
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
cfile = malloc(flen);
if (cfile == NULL)
return NULL;
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
ctrl_conn = wpa_ctrl_open(cfile);
free(cfile);
return ctrl_conn;
}
static void hostapd_cli_close_connection(void)
{
if (ctrl_conn == NULL)
return;
if (hostapd_cli_attached) {
wpa_ctrl_detach(ctrl_conn);
hostapd_cli_attached = 0;
}
wpa_ctrl_close(ctrl_conn);
ctrl_conn = NULL;
}
static void hostapd_cli_msg_cb(char *msg, size_t len)
{
printf("%s\n", msg);
}
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
{
char buf[4096];
size_t len;
int ret;
if (ctrl_conn == NULL) {
printf("Not connected to hostapd - command dropped.\n");
return -1;
}
len = sizeof(buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
hostapd_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
return -2;
} else if (ret < 0) {
printf("'%s' command failed.\n", cmd);
return -1;
}
if (print) {
buf[len] = '\0';
printf("%s", buf);
}
return 0;
}
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
{
return _wpa_ctrl_command(ctrl, cmd, 1);
}
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "PING");
}
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "MIB");
}
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char buf[64];
if (argc != 1) {
printf("Invalid 'sta' command - exactly one argument, STA "
"address, is required.\n");
return -1;
}
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
if (argc != 1) {
printf("Invalid 'new_sta' command - exactly one argument, STA "
"address, is required.\n");
return -1;
}
snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
if (argc != 1) {
printf("Invalid 'sa_query' command - exactly one argument, "
"STA address, is required.\n");
return -1;
}
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
if (argc != 2) {
printf("Invalid 'wps_pin' command - exactly two arguments, "
"UUID and PIN, are required.\n");
return -1;
}
snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
return wpa_ctrl_command(ctrl, buf);
}
static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "WPS_PBC");
}
#endif /* CONFIG_WPS */
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
char *addr, size_t addr_len)
{
char buf[4096], *pos;
size_t len;
int ret;
if (ctrl_conn == NULL) {
printf("Not connected to hostapd - command dropped.\n");
return -1;
}
len = sizeof(buf) - 1;
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
hostapd_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
return -2;
} else if (ret < 0) {
printf("'%s' command failed.\n", cmd);
return -1;
}
buf[len] = '\0';
if (memcmp(buf, "FAIL", 4) == 0)
return -1;
printf("%s", buf);
pos = buf;
while (*pos != '\0' && *pos != '\n')
pos++;
*pos = '\0';
os_strlcpy(addr, buf, addr_len);
return 0;
}
static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char addr[32], cmd[64];
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
return 0;
do {
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
return -1;
}
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
printf("%s", commands_help);
return 0;
}
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
return 0;
}
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
hostapd_cli_quit = 1;
return 0;
}
static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
if (argc != 1) {
printf("Invalid LEVEL command: needs one argument (debug "
"level)\n");
return 0;
}
snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
return wpa_ctrl_command(ctrl, cmd);
}
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
struct dirent *dent;
DIR *dir;
dir = opendir(ctrl_iface_dir);
if (dir == NULL) {
printf("Control interface directory '%s' could not be "
"openned.\n", ctrl_iface_dir);
return;
}
printf("Available interfaces:\n");
while ((dent = readdir(dir))) {
if (strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0)
continue;
printf("%s\n", dent->d_name);
}
closedir(dir);
}
static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
if (argc < 1) {
hostapd_cli_list_interfaces(ctrl);
return 0;
}
hostapd_cli_close_connection();
free(ctrl_ifname);
ctrl_ifname = strdup(argv[0]);
if (hostapd_cli_open_connection(ctrl_ifname)) {
printf("Connected to interface '%s.\n", ctrl_ifname);
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
} else {
printf("Warning: Failed to attach to "
"hostapd.\n");
}
} else {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
}
return 0;
}
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
};
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query },
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin },
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
#endif /* CONFIG_WPS */
{ "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 },
{ NULL, NULL }
};
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
struct hostapd_cli_cmd *cmd, *match = NULL;
int count;
count = 0;
cmd = hostapd_cli_commands;
while (cmd->cmd) {
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
match = cmd;
count++;
}
cmd++;
}
if (count > 1) {
printf("Ambiguous command '%s'; possible commands:", argv[0]);
cmd = hostapd_cli_commands;
while (cmd->cmd) {
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
0) {
printf(" %s", cmd->cmd);
}
cmd++;
}
printf("\n");
} else if (count == 0) {
printf("Unknown command '%s'\n", argv[0]);
} else {
match->handler(ctrl, argc - 1, &argv[1]);
}
}
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
{
int first = 1;
if (ctrl_conn == NULL)
return;
while (wpa_ctrl_pending(ctrl)) {
char buf[256];
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
buf[len] = '\0';
if (in_read && first)
printf("\n");
first = 0;
printf("%s\n", buf);
} else {
printf("Could not read pending message.\n");
break;
}
}
}
static void hostapd_cli_interactive(void)
{
const int max_args = 10;
char cmd[256], *res, *argv[max_args], *pos;
int argc;
printf("\nInteractive mode\n\n");
do {
hostapd_cli_recv_pending(ctrl_conn, 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++;
}
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);
}
static void hostapd_cli_terminate(int sig)
{
hostapd_cli_close_connection();
exit(0);
}
static void hostapd_cli_alarm(int sig)
{
if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
printf("Connection to hostapd lost - trying to reconnect\n");
hostapd_cli_close_connection();
}
if (!ctrl_conn) {
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
if (ctrl_conn) {
printf("Connection to hostapd re-established\n");
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
} else {
printf("Warning: Failed to attach to "
"hostapd.\n");
}
}
}
if (ctrl_conn)
hostapd_cli_recv_pending(ctrl_conn, 1);
alarm(ping_interval);
}
int main(int argc, char *argv[])
{
int interactive;
int warning_displayed = 0;
int c;
for (;;) {
c = getopt(argc, argv, "hG:i:p:v");
if (c < 0)
break;
switch (c) {
case 'G':
ping_interval = atoi(optarg);
break;
case 'h':
usage();
return 0;
case 'v':
printf("%s\n", hostapd_cli_version);
return 0;
case 'i':
free(ctrl_ifname);
ctrl_ifname = strdup(optarg);
break;
case 'p':
ctrl_iface_dir = optarg;
break;
default:
usage();
return -1;
}
}
interactive = argc == optind;
if (interactive) {
printf("%s\n\n%s\n\n", hostapd_cli_version,
hostapd_cli_license);
}
for (;;) {
if (ctrl_ifname == NULL) {
struct dirent *dent;
DIR *dir = opendir(ctrl_iface_dir);
if (dir) {
while ((dent = readdir(dir))) {
if (strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0)
continue;
printf("Selected interface '%s'\n",
dent->d_name);
ctrl_ifname = strdup(dent->d_name);
break;
}
closedir(dir);
}
}
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)
printf("Connection established.\n");
break;
}
if (!interactive) {
perror("Failed to connect to hostapd - "
"wpa_ctrl_open");
return -1;
}
if (!warning_displayed) {
printf("Could not connect to hostapd - re-trying\n");
warning_displayed = 1;
}
sleep(1);
continue;
}
signal(SIGINT, hostapd_cli_terminate);
signal(SIGTERM, hostapd_cli_terminate);
signal(SIGALRM, hostapd_cli_alarm);
if (interactive) {
if (wpa_ctrl_attach(ctrl_conn) == 0) {
hostapd_cli_attached = 1;
} else {
printf("Warning: Failed to attach to hostapd.\n");
}
hostapd_cli_interactive();
} else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
free(ctrl_ifname);
hostapd_cli_close_connection();
return 0;
}

487
hostapd/hw_features.c Normal file
View File

@ -0,0 +1,487 @@
/*
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "hw_features.h"
#include "driver.h"
#include "config.h"
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features)
{
size_t i;
if (hw_features == NULL)
return;
for (i = 0; i < num_hw_features; i++) {
os_free(hw_features[i].channels);
os_free(hw_features[i].rates);
}
os_free(hw_features);
}
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
int ret = 0, i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
if (hostapd_drv_none(hapd))
return -1;
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
if (modes == NULL) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Fetching hardware channel/rate support not "
"supported.");
return -1;
}
iface->hw_flags = flags;
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = modes;
iface->num_hw_features = num_modes;
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *feature = &modes[i];
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
/*
* Disable all channels that are marked not to allow
* IBSS operation or active scanning. In addition,
* disable all channels that require radar detection,
* since that (in addition to full DFS) is not yet
* supported.
*/
if (feature->channels[j].flag &
(HOSTAPD_CHAN_NO_IBSS |
HOSTAPD_CHAN_PASSIVE_SCAN |
HOSTAPD_CHAN_RADAR))
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
"chan=%d freq=%d MHz max_tx_power=%d dBm",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
feature->channels[j].max_tx_power);
}
}
return ret;
}
static int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode)
{
int i, num_basic_rates = 0;
int basic_rates_a[] = { 60, 120, 240, -1 };
int basic_rates_b[] = { 10, 20, -1 };
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
int *basic_rates;
if (hapd->iconf->basic_rates)
basic_rates = hapd->iconf->basic_rates;
else switch (mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
basic_rates = basic_rates_a;
break;
case HOSTAPD_MODE_IEEE80211B:
basic_rates = basic_rates_b;
break;
case HOSTAPD_MODE_IEEE80211G:
basic_rates = basic_rates_g;
break;
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");
}
os_free(hapd->iface->current_rates);
hapd->iface->num_rates = 0;
hapd->iface->current_rates =
os_malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
if (!hapd->iface->current_rates) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
"table.");
return -1;
}
for (i = 0; i < mode->num_rates; i++) {
struct hostapd_rate_data *rate;
if (hapd->iconf->supported_rates &&
!hostapd_rate_found(hapd->iconf->supported_rates,
mode->rates[i].rate))
continue;
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
os_memcpy(rate, &mode->rates[i],
sizeof(struct hostapd_rate_data));
if (hostapd_rate_found(basic_rates, rate->rate)) {
rate->flags |= HOSTAPD_RATE_BASIC;
num_basic_rates++;
} else
rate->flags &= ~HOSTAPD_RATE_BASIC;
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
hapd->iface->num_rates, rate->rate, rate->flags);
hapd->iface->num_rates++;
}
if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
"rate sets (%d,%d).",
hapd->iface->num_rates, num_basic_rates);
return -1;
}
return 0;
}
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int sec_chan, ok, j, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
size_t k;
if (!iface->conf->secondary_channel)
return 1; /* HT40 not used */
sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
"secondary channel: %d",
iface->conf->channel, sec_chan);
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
ok = 0;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
chan->chan == sec_chan) {
ok = 1;
break;
}
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
sec_chan);
return 0;
}
/*
* Verify that HT40 primary,secondary channel pair is allowed per
* IEEE 802.11n Annex J. This is only needed for 5 GHz band since
* 2.4 GHz rules allow all cases where the secondary channel fits into
* the list of allowed channels (already checked above).
*/
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return 1;
if (iface->conf->secondary_channel > 0)
first = iface->conf->channel;
else
first = sec_chan;
ok = 0;
for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
if (first == allowed[k]) {
ok = 1;
break;
}
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
iface->conf->channel,
iface->conf->secondary_channel);
return 0;
}
return 1;
}
static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
{
u16 hw = iface->current_mode->ht_capab;
u16 conf = iface->conf->ht_capab;
if (!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 "
"HT capability [LDPC]");
return 0;
}
if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [HT40*]");
return 0;
}
if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
(conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SMPS-*]");
return 0;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [GF]");
return 0;
}
if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
!(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SHORT-GI-20]");
return 0;
}
if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
!(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SHORT-GI-40]");
return 0;
}
if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [TX-STBC]");
return 0;
}
if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
(hw & HT_CAP_INFO_RX_STBC_MASK)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [RX-STBC*]");
return 0;
}
if ((conf & HT_CAP_INFO_DELAYED_BA) &&
!(hw & HT_CAP_INFO_DELAYED_BA)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [DELAYED-BA]");
return 0;
}
if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
!(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [MAX-AMSDU-7935]");
return 0;
}
if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
!(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [DSSS_CCK-40]");
return 0;
}
if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [PSMP]");
return 0;
}
if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
!(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [LSIG-TXOP-PROT]");
return 0;
}
return 1;
}
#endif /* CONFIG_IEEE80211N */
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
*
* Sets up the hardware mode, channel, rates, and passive scanning
* based on the configuration.
*/
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i, j, ok, ret;
if (iface->num_hw_features < 1)
return -1;
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == (int) iface->conf->hw_mode) {
iface->current_mode = mode;
break;
}
}
if (iface->current_mode == NULL) {
wpa_printf(MSG_ERROR, "Hardware does not support configured "
"mode");
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured mode "
"(%d)", (int) iface->conf->hw_mode);
return -1;
}
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 (ok == 0 && iface->conf->channel != 0) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured channel (%d) not found from the "
"channel list of current mode (%d) %s",
iface->conf->channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
iface->current_mode = NULL;
}
if (iface->current_mode == NULL) {
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
return -1;
}
#ifdef CONFIG_IEEE80211N
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211N */
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;
}
ret = hostapd_passive_scan(iface->bss[0], 0,
iface->conf->passive_scan_mode,
iface->conf->passive_scan_interval,
iface->conf->passive_scan_listen,
NULL, NULL);
if (ret) {
if (ret == -1) {
wpa_printf(MSG_DEBUG, "Passive scanning not "
"supported");
} else {
wpa_printf(MSG_ERROR, "Could not set passive "
"scanning: %s", strerror(ret));
}
ret = 0;
}
return ret;
}
const char * hostapd_hw_mode_txt(int mode)
{
switch (mode) {
case HOSTAPD_MODE_IEEE80211A:
return "IEEE 802.11a";
case HOSTAPD_MODE_IEEE80211B:
return "IEEE 802.11b";
case HOSTAPD_MODE_IEEE80211G:
return "IEEE 802.11g";
default:
return "UNKNOWN";
}
}
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
{
int i;
if (!hapd->iface->current_mode)
return 0;
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
struct hostapd_channel_data *ch =
&hapd->iface->current_mode->channels[i];
if (ch->chan == chan)
return ch->freq;
}
return 0;
}
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
{
int i;
if (!hapd->iface->current_mode)
return 0;
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
struct hostapd_channel_data *ch =
&hapd->iface->current_mode->channels[i];
if (ch->freq == freq)
return ch->chan;
}
return 0;
}

62
hostapd/hw_features.h Normal file
View File

@ -0,0 +1,62 @@
/*
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef HW_FEATURES_H
#define HW_FEATURES_H
#define HOSTAPD_CHAN_DISABLED 0x00000001
#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
#define HOSTAPD_CHAN_NO_IBSS 0x00000004
#define HOSTAPD_CHAN_RADAR 0x00000008
struct hostapd_channel_data {
short chan; /* channel number (IEEE 802.11) */
short freq; /* frequency in MHz */
int flag; /* flag for hostapd use (HOSTAPD_CHAN_*) */
u8 max_tx_power; /* maximum transmit power in dBm */
};
#define HOSTAPD_RATE_ERP 0x00000001
#define HOSTAPD_RATE_BASIC 0x00000002
#define HOSTAPD_RATE_PREAMBLE2 0x00000004
#define HOSTAPD_RATE_SUPPORTED 0x00000010
#define HOSTAPD_RATE_OFDM 0x00000020
#define HOSTAPD_RATE_CCK 0x00000040
#define HOSTAPD_RATE_MANDATORY 0x00000100
struct hostapd_rate_data {
int rate; /* rate in 100 kbps */
int flags; /* HOSTAPD_RATE_ flags */
};
struct hostapd_hw_modes {
int mode;
int num_channels;
struct hostapd_channel_data *channels;
int num_rates;
struct hostapd_rate_data *rates;
u16 ht_capab;
};
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
#endif /* HW_FEATURES_H */

553
hostapd/iapp.c Normal file
View File

@ -0,0 +1,553 @@
/*
* 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.
*
* 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
* using some other mechanism for AP-to-AP communication than extending the
* implementation here.
*/
/* TODO:
* Level 1: no administrative or security support
* (e.g., static BSSID to IP address mapping in each AP)
* Level 2: support for dynamic mapping of BSSID to IP address
* Level 3: support for encryption and authentication of IAPP messages
* - add support for MOVE-notify and MOVE-response (this requires support for
* finding out IP address for previous AP using RADIUS)
* - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
* reassociation to another AP
* - implement counters etc. for IAPP MIB
* - verify endianness of fields in IAPP messages; are they big-endian as
* used here?
* - RADIUS connection for AP registration and BSSID to IP address mapping
* - TCP connection for IAPP MOVE, CACHE
* - broadcast ESP for IAPP ADD-notify
* - ESP for IAPP MOVE messages
* - security block sending/processing
* - IEEE 802.11 context transfer
*/
#include "includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
#ifdef USE_KERNEL_HEADERS
#include <linux/if_packet.h>
#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
#endif /* USE_KERNEL_HEADERS */
#include "hostapd.h"
#include "ieee802_11.h"
#include "iapp.h"
#include "eloop.h"
#include "sta_info.h"
#define IAPP_MULTICAST "224.0.1.178"
#define IAPP_UDP_PORT 3517
#define IAPP_TCP_PORT 3517
struct iapp_hdr {
u8 version;
u8 command;
be16 identifier;
be16 length;
/* followed by length-6 octets of data */
} __attribute__ ((packed));
#define IAPP_VERSION 0
enum IAPP_COMMAND {
IAPP_CMD_ADD_notify = 0,
IAPP_CMD_MOVE_notify = 1,
IAPP_CMD_MOVE_response = 2,
IAPP_CMD_Send_Security_Block = 3,
IAPP_CMD_ACK_Security_Block = 4,
IAPP_CMD_CACHE_notify = 5,
IAPP_CMD_CACHE_response = 6,
};
/* ADD-notify - multicast UDP on the local LAN */
struct iapp_add_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
be16 seq_num;
} __attribute__ ((packed));
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
u8 da[ETH_ALEN]; /* broadcast */
u8 sa[ETH_ALEN]; /* STA addr */
be16 len; /* 6 */
u8 dsap; /* null DSAP address */
u8 ssap; /* null SSAP address, CR=Response */
u8 control;
u8 xid_info[3];
} __attribute__ ((packed));
/* MOVE-notify - unicast TCP */
struct iapp_move_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u16 ctx_block_len;
/* followed by ctx_block_len bytes */
} __attribute__ ((packed));
/* MOVE-response - unicast TCP */
struct iapp_move_response {
u8 addr_len; /* ETH_ALEN */
u8 status;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u16 ctx_block_len;
/* followed by ctx_block_len bytes */
} __attribute__ ((packed));
enum {
IAPP_MOVE_SUCCESSFUL = 0,
IAPP_MOVE_DENIED = 1,
IAPP_MOVE_STALE_MOVE = 2,
};
/* CACHE-notify */
struct iapp_cache_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u8 current_ap[ETH_ALEN];
u16 ctx_block_len;
/* ctx_block_len bytes of context block followed by 16-bit context
* timeout */
} __attribute__ ((packed));
/* CACHE-response - unicast TCP */
struct iapp_cache_response {
u8 addr_len; /* ETH_ALEN */
u8 status;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
} __attribute__ ((packed));
enum {
IAPP_CACHE_SUCCESSFUL = 0,
IAPP_CACHE_STALE_CACHE = 1,
};
/* Send-Security-Block - unicast TCP */
struct iapp_send_security_block {
u8 iv[8];
u16 sec_block_len;
/* followed by sec_block_len bytes of security block */
} __attribute__ ((packed));
/* ACK-Security-Block - unicast TCP */
struct iapp_ack_security_block {
u8 iv[8];
u8 new_ap_ack_authenticator[48];
} __attribute__ ((packed));
struct iapp_data {
struct hostapd_data *hapd;
u16 identifier; /* next IAPP identifier */
struct in_addr own, multicast;
int udp_sock;
int packet_sock;
};
static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
{
char buf[128];
struct iapp_hdr *hdr;
struct iapp_add_notify *add;
struct sockaddr_in addr;
/* Send IAPP ADD-notify to remove possible association from other APs
*/
hdr = (struct iapp_hdr *) buf;
hdr->version = IAPP_VERSION;
hdr->command = IAPP_CMD_ADD_notify;
hdr->identifier = host_to_be16(iapp->identifier++);
hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
add = (struct iapp_add_notify *) (hdr + 1);
add->addr_len = ETH_ALEN;
add->reserved = 0;
os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
add->seq_num = host_to_be16(seq_num);
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = iapp->multicast.s_addr;
addr.sin_port = htons(IAPP_UDP_PORT);
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
(struct sockaddr *) &addr, sizeof(addr)) < 0)
perror("sendto[IAPP-ADD]");
}
static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
{
struct iapp_layer2_update msg;
/* Send Level 2 Update Frame to update forwarding tables in layer 2
* bridge devices */
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
os_memset(msg.da, 0xff, ETH_ALEN);
os_memcpy(msg.sa, addr, ETH_ALEN);
msg.len = host_to_be16(6);
msg.dsap = 0; /* NULL DSAP address */
msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
msg.control = 0xaf; /* XID response lsb.1111F101.
* F=0 (no poll command; unsolicited frame) */
msg.xid_info[0] = 0x81; /* XID format identifier */
msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
* FIX: what is correct RW with 802.11? */
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
perror("send[L2 Update]");
}
/**
* iapp_new_station - IAPP processing for a new STA
* @iapp: IAPP data
* @sta: The associated station
*/
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
{
struct ieee80211_mgmt *assoc;
u16 seq;
if (iapp == NULL)
return;
assoc = sta->last_assoc_req;
seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
iapp_send_layer2_update(iapp, sta->addr);
iapp_send_add(iapp, sta->addr, seq);
if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
WLAN_FC_STYPE_REASSOC_REQ) {
/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
* Context Block, Timeout)
*/
/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
* IP address */
}
}
static void iapp_process_add_notify(struct iapp_data *iapp,
struct sockaddr_in *from,
struct iapp_hdr *hdr, int len)
{
struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
struct sta_info *sta;
if (len != sizeof(*add)) {
printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
len, (unsigned long) sizeof(*add));
return;
}
sta = ap_get_sta(iapp->hapd, add->mac_addr);
/* IAPP-ADD.indication(MAC Address, Sequence Number) */
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_INFO,
"Received IAPP ADD-notify (seq# %d) from %s:%d%s",
be_to_host16(add->seq_num),
inet_ntoa(from->sin_addr), ntohs(from->sin_port),
sta ? "" : " (STA not found)");
if (!sta)
return;
/* TODO: could use seq_num to try to determine whether last association
* to this AP is newer than the one advertised in IAPP-ADD. Although,
* this is not really a reliable verification. */
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"Removing STA due to IAPP ADD-notify");
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
eloop_cancel_timeout(ap_handle_timer, iapp->hapd, sta);
eloop_register_timeout(0, 0, ap_handle_timer, iapp->hapd, sta);
sta->timeout_next = STA_REMOVE;
}
/**
* iapp_receive_udp - Process IAPP UDP frames
* @sock: File descriptor for the socket
* @eloop_ctx: IAPP data (struct iapp_data *)
* @sock_ctx: Not used
*/
static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
{
struct iapp_data *iapp = eloop_ctx;
int len, hlen;
unsigned char buf[128];
struct sockaddr_in from;
socklen_t fromlen;
struct iapp_hdr *hdr;
/* Handle incoming IAPP frames (over UDP/IP) */
fromlen = sizeof(from);
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
(struct sockaddr *) &from, &fromlen);
if (len < 0) {
perror("recvfrom");
return;
}
if (from.sin_addr.s_addr == iapp->own.s_addr)
return; /* ignore own IAPP messages */
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"Received %d byte IAPP frame from %s%s\n",
len, inet_ntoa(from.sin_addr),
len < (int) sizeof(*hdr) ? " (too short)" : "");
if (len < (int) sizeof(*hdr))
return;
hdr = (struct iapp_hdr *) buf;
hlen = be_to_host16(hdr->length);
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"RX: version=%d command=%d id=%d len=%d\n",
hdr->version, hdr->command,
be_to_host16(hdr->identifier), hlen);
if (hdr->version != IAPP_VERSION) {
printf("Dropping IAPP frame with unknown version %d\n",
hdr->version);
return;
}
if (hlen > len) {
printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
return;
}
if (hlen < len) {
printf("Ignoring %d extra bytes from IAPP frame\n",
len - hlen);
len = hlen;
}
switch (hdr->command) {
case IAPP_CMD_ADD_notify:
iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
break;
case IAPP_CMD_MOVE_notify:
/* TODO: MOVE is using TCP; so move this to TCP handler once it
* is implemented.. */
/* IAPP-MOVE.indication(MAC Address, New BSSID,
* Sequence Number, AP Address, Context Block) */
/* TODO: process */
break;
default:
printf("Unknown IAPP command %d\n", hdr->command);
break;
}
}
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
{
struct ifreq ifr;
struct sockaddr_ll addr;
int ifindex;
struct sockaddr_in *paddr, uaddr;
struct iapp_data *iapp;
struct ip_mreqn mreq;
iapp = os_zalloc(sizeof(*iapp));
if (iapp == NULL)
return NULL;
iapp->hapd = hapd;
iapp->udp_sock = iapp->packet_sock = -1;
/* TODO:
* open socket for sending and receiving IAPP frames over TCP
*/
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (iapp->udp_sock < 0) {
perror("socket[PF_INET,SOCK_DGRAM]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
perror("ioctl(SIOCGIFINDEX)");
iapp_deinit(iapp);
return NULL;
}
ifindex = ifr.ifr_ifindex;
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFADDR)");
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFADDR)\n",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
iapp->own.s_addr = paddr->sin_addr.s_addr;
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFBRDADDR)");
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
inet_aton(IAPP_MULTICAST, &iapp->multicast);
os_memset(&uaddr, 0, sizeof(uaddr));
uaddr.sin_family = AF_INET;
uaddr.sin_port = htons(IAPP_UDP_PORT);
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
perror("bind[UDP]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = iapp->multicast;
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
iapp_deinit(iapp);
return NULL;
}
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (iapp->packet_sock < 0) {
perror("socket[PF_PACKET,SOCK_RAW]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifindex;
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
perror("bind[PACKET]");
iapp_deinit(iapp);
return NULL;
}
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
iapp, NULL)) {
printf("Could not register read socket for IAPP.\n");
iapp_deinit(iapp);
return NULL;
}
printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
* be openned only after receiving Initiate-Accept. If Initiate-Reject
* is received, IAPP is not started. */
return iapp;
}
void iapp_deinit(struct iapp_data *iapp)
{
struct ip_mreqn mreq;
if (iapp == NULL)
return;
if (iapp->udp_sock >= 0) {
os_memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = iapp->multicast;
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
}
eloop_unregister_read_sock(iapp->udp_sock);
close(iapp->udp_sock);
}
if (iapp->packet_sock >= 0) {
eloop_unregister_read_sock(iapp->packet_sock);
close(iapp->packet_sock);
}
os_free(iapp);
}
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss)
{
if (hapd->conf->ieee802_11f != oldbss->ieee802_11f ||
os_strcmp(hapd->conf->iapp_iface, oldbss->iapp_iface) != 0) {
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
if (hapd->conf->ieee802_11f) {
hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface);
if (hapd->iapp == NULL)
return -1;
}
}
return 0;
}

54
hostapd/iapp.h Normal file
View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef IAPP_H
#define IAPP_H
struct iapp_data;
#ifdef CONFIG_IAPP
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
void iapp_deinit(struct iapp_data *iapp);
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss);
#else /* CONFIG_IAPP */
static inline void iapp_new_station(struct iapp_data *iapp,
struct sta_info *sta)
{
}
static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
const char *iface)
{
return NULL;
}
static inline void iapp_deinit(struct iapp_data *iapp)
{
}
static inline int
iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss)
{
return 0;
}
#endif /* CONFIG_IAPP */
#endif /* IAPP_H */

1768
hostapd/ieee802_11.c Normal file

File diff suppressed because it is too large Load Diff

56
hostapd/ieee802_11.h Normal file
View File

@ -0,0 +1,56 @@
/*
* hostapd / IEEE 802.11 Management
* Copyright (c) 2002-2006, 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.
*/
#ifndef IEEE802_11_H
#define IEEE802_11_H
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
struct hostapd_frame_info {
u32 phytype;
u32 channel;
u32 datarate;
u32 ssi_signal;
unsigned int passive_scan:1;
};
struct hostapd_iface;
struct hostapd_data;
struct sta_info;
void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason);
void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len,
u16 stype, struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
u16 stype, int ok);
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
int local);
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
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_info(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_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);
#endif /* IEEE802_11_H */

523
hostapd/ieee802_11_auth.c Normal file
View File

@ -0,0 +1,523 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-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.
*
* Access control list for IEEE 802.11 authentication can uses statically
* configured ACL from configuration files or an external RADIUS server.
* Results from external RADIUS queries are cached to allow faster
* authentication frame processing.
*/
#include "includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include "hostapd.h"
#include "ieee802_11.h"
#include "ieee802_11_auth.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "eloop.h"
#include "driver.h"
#define RADIUS_ACL_TIMEOUT 30
struct hostapd_cached_radius_acl {
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_acl_query_data {
time_t timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
size_t auth_msg_len;
struct hostapd_acl_query_data *next;
};
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
{
struct hostapd_cached_radius_acl *prev;
while (acl_cache) {
prev = acl_cache;
acl_cache = acl_cache->next;
os_free(prev);
}
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id)
{
struct hostapd_cached_radius_acl *entry;
time_t now;
time(&now);
entry = hapd->acl_cache;
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;
}
entry = entry->next;
}
return -1;
}
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
{
if (query == NULL)
return;
os_free(query->auth_msg);
os_free(query);
}
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
struct hostapd_acl_query_data *query)
{
struct radius_msg *msg;
char buf[128];
query->radius_id = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
if (msg == NULL)
return -1;
radius_msg_make_authenticator(msg, addr, ETH_ALEN);
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add User-Name");
goto fail;
}
if (!radius_msg_add_attr_user_password(
msg, (u8 *) buf, os_strlen(buf),
hapd->conf->radius->auth_server->shared_secret,
hapd->conf->radius->auth_server->shared_secret_len)) {
wpa_printf(MSG_DEBUG, "Could not add User-Password");
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");
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));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
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))) {
wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
goto fail;
}
radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
return 0;
fail:
radius_msg_free(msg);
os_free(msg);
return -1;
}
/**
* hostapd_allowed_address - Check whether a specified STA can be authenticated
* @hapd: hostapd BSS data
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
* @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
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*/
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)
{
if (session_timeout)
*session_timeout = 0;
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
return HOSTAPD_ACL_ACCEPT;
if (hostapd_maclist_found(hapd->conf->deny_mac,
hapd->conf->num_deny_mac, addr, vlan_id))
return HOSTAPD_ACL_REJECT;
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
return HOSTAPD_ACL_ACCEPT;
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
return HOSTAPD_ACL_REJECT;
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
struct hostapd_acl_query_data *query;
/* 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);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
if (res == HOSTAPD_ACL_REJECT)
return HOSTAPD_ACL_REJECT;
query = hapd->acl_queries;
while (query) {
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
return HOSTAPD_ACL_PENDING;
}
query = query->next;
}
if (!hapd->conf->radius->auth_server)
return HOSTAPD_ACL_REJECT;
/* No entry in the cache - query external RADIUS server */
query = os_zalloc(sizeof(*query));
if (query == NULL) {
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
time(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
"for ACL query.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
query->auth_msg = os_malloc(len);
if (query->auth_msg == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
os_memcpy(query->auth_msg, msg, len);
query->auth_msg_len = len;
query->next = hapd->acl_queries;
hapd->acl_queries = query;
/* Queued data will be processed in hostapd_acl_recv_radius()
* when RADIUS server replies to the sent Access-Request. */
return HOSTAPD_ACL_PENDING;
}
return HOSTAPD_ACL_REJECT;
}
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
prev = NULL;
entry = hapd->acl_cache;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
prev->next = entry->next;
else
hapd->acl_cache = entry->next;
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_set_radius_acl_expire(hapd, entry->addr);
#endif /* CONFIG_DRIVER_RADIUS_ACL */
tmp = entry;
entry = entry->next;
os_free(tmp);
continue;
}
prev = entry;
entry = entry->next;
}
}
static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
prev = NULL;
entry = hapd->acl_queries;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
prev->next = entry->next;
else
hapd->acl_queries = entry->next;
tmp = entry;
entry = entry->next;
hostapd_acl_query_free(tmp);
continue;
}
prev = entry;
entry = entry->next;
}
}
/**
* hostapd_acl_expire - ACL cache expiration callback
* @eloop_ctx: struct hostapd_data *
* @timeout_ctx: Not used
*/
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
time_t now;
time(&now);
hostapd_acl_expire_cache(hapd, now);
hostapd_acl_expire_queries(hapd, now);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message
* @req: RADIUS request message
* @shared_secret: RADIUS shared secret
* @shared_secret_len: Length of shared_secret in octets
* @data: Context data (struct hostapd_data *)
* Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
* was processed here) or RADIUS_RX_UNKNOWN if not.
*/
static RadiusRxResult
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
query = hapd->acl_queries;
prev = NULL;
while (query) {
if (query->radius_id == msg->hdr->identifier)
break;
prev = query;
query = query->next;
}
if (query == NULL)
return RADIUS_RX_UNKNOWN;
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
"message (id=%d)", query->radius_id);
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
"correct authenticator - dropped\n");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
"query", msg->hdr->code);
return RADIUS_RX_UNKNOWN;
}
/* Insert Accept/Reject info into ACL cache */
cache = os_zalloc(sizeof(*cache));
if (cache == NULL) {
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
time(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&cache->acct_interim_interval) == 0 &&
cache->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
cache->acct_interim_interval,
MAC2STR(query->addr));
cache->acct_interim_interval = 0;
}
cache->vlan_id = radius_msg_get_vlanid(msg);
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_set_radius_acl_auth(hapd, query->addr, cache->accepted,
cache->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
/* Re-send original authentication frame for 802.11 processing */
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
"successful RADIUS ACL query");
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
WLAN_FC_STYPE_AUTH, NULL);
#endif /* CONFIG_DRIVER_RADIUS_ACL */
done:
if (prev == NULL)
hapd->acl_queries = query->next;
else
prev->next = query->next;
hostapd_acl_query_free(query);
return RADIUS_RX_PROCESSED;
}
/**
* hostapd_acl_init: Initialize IEEE 802.11 ACL
* @hapd: hostapd BSS data
* Returns: 0 on success, -1 on failure
*/
int hostapd_acl_init(struct hostapd_data *hapd)
{
if (radius_client_register(hapd->radius, RADIUS_AUTH,
hostapd_acl_recv_radius, hapd))
return -1;
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
return 0;
}
/**
* hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
* @hapd: hostapd BSS data
*/
void hostapd_acl_deinit(struct hostapd_data *hapd)
{
struct hostapd_acl_query_data *query, *prev;
eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
hostapd_acl_cache_free(hapd->acl_cache);
query = hapd->acl_queries;
while (query) {
prev = query;
query = query->next;
hostapd_acl_query_free(prev);
}
}
int hostapd_acl_reconfig(struct hostapd_data *hapd,
struct hostapd_config *oldconf)
{
if (!hapd->radius_client_reconfigured)
return 0;
hostapd_acl_deinit(hapd);
return hostapd_acl_init(hapd);
}
#endif /* CONFIG_NATIVE_WINDOWS */

33
hostapd/ieee802_11_auth.h Normal file
View File

@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef IEEE802_11_AUTH_H
#define IEEE802_11_AUTH_H
enum {
HOSTAPD_ACL_REJECT = 0,
HOSTAPD_ACL_ACCEPT = 1,
HOSTAPD_ACL_PENDING = 2,
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
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);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
int hostapd_acl_reconfig(struct hostapd_data *hapd,
struct hostapd_config *oldconf);
#endif /* IEEE802_11_AUTH_H */

2042
hostapd/ieee802_1x.c Normal file

File diff suppressed because it is too large Load Diff

90
hostapd/ieee802_1x.h Normal file
View File

@ -0,0 +1,90 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
* 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.
*/
#ifndef IEEE802_1X_H
#define IEEE802_1X_H
struct hostapd_data;
struct sta_info;
struct eapol_state_machine;
struct hostapd_config;
struct hostapd_bss_config;
/* 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 */
} __attribute__ ((packed));
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len);
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct sta_info *sta);
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
int ieee802_1x_init(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_reconfig(struct hostapd_data *hapd,
struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t 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);
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);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
int valid);
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
void hostapd_get_ntp_timestamp(u8 *buf);
char *eap_type_text(u8 type);
struct radius_class_data;
void ieee802_1x_free_radius_class(struct radius_class_data *class);
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
const struct radius_class_data *src);
const char *radius_mode_txt(struct hostapd_data *hapd);
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* IEEE802_1X_H */

9
hostapd/logwatch/README Normal file
View File

@ -0,0 +1,9 @@
Logwatch is a utility for analyzing system logs and provide a human
readable summary. This directory has a configuration file and a log
analyzer script for parsing hostapd system log entries for logwatch.
These files can be installed by copying them to following locations:
/etc/log.d/conf/services/hostapd.conf
/etc/log.d/scripts/services/hostapd
More information about logwatch is available from http://www.logwatch.org/

65
hostapd/logwatch/hostapd Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/perl -w
#
# Logwatch script for hostapd
#
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
# Distributed under the terms of the GNU General Public License v2
# Alternatively, this file may be distributed under the terms of the BSD License
use strict;
my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
my $debugcounter = 1;
my %hostapd;
my @unmatched;
if ($debug >= 5) {
print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
}
while (defined(my $line = <STDIN>)) {
if ($debug >= 5) {
print STDERR "DEBUG($debugcounter): $line";
$debugcounter++;
}
chomp($line);
if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
unless ($detail == 10) {
# collapse association events
$details =~ s/^(associated) .*$/$1/i;
}
$hostapd{$iface}->{$mac}->{$layer}->{$details}++;
} else {
push @unmatched, "$line\n";
}
}
if (keys %hostapd) {
foreach my $iface (sort keys %hostapd) {
print "Interface $iface:\n";
foreach my $mac (sort keys %{$hostapd{$iface}}) {
print " Client MAC Address $mac:\n";
foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
print " $layer:\n";
foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
print " $details";
my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
if ($count > 1) {
print ": " . $count . " Times";
}
print "\n";
}
}
}
}
}
if ($#unmatched >= 0) {
print "\n**Unmatched Entries**\n";
print @unmatched;
}
exit(0);

View File

@ -0,0 +1,10 @@
# Logwatch configuration for hostapd
#
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
# Distributed under the terms of the GNU General Public License v2
# Alternatively, this file may be distributed under the terms of the BSD License
Title = "hostapd"
LogFile = messages
*OnlyService = hostapd
*RemoveHeaders

180
hostapd/mlme.c Normal file
View File

@ -0,0 +1,180 @@
/*
* hostapd / IEEE 802.11 MLME
* Copyright 2003-2006, Jouni Malinen <j@w1.fi>
* 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "wpa.h"
#include "mlme.h"
static const char * mlme_auth_alg_str(int alg)
{
switch (alg) {
case WLAN_AUTH_OPEN:
return "OPEN_SYSTEM";
case WLAN_AUTH_SHARED_KEY:
return "SHARED_KEY";
case WLAN_AUTH_FT:
return "FT";
}
return "unknown";
}
/**
* mlme_authenticate_indication - Report the establishment of an authentication
* relationship with a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* authentication relationship with a specific peer MAC entity that
* resulted from an authentication procedure that was initiated by
* that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
* AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
*/
void mlme_authenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_deauthenticate_indication - Report the invalidation of an
* authentication relationship with a specific peer MAC entity
* @hapd: BSS data
* @sta: Peer STA data
* @reason_code: ReasonCode from Deauthentication frame
*
* MLME calls this function as a result of the invalidation of an
* authentication relationship with a specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_associate_indication - Report the establishment of an association with
* a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* association with a specific peer MAC entity that resulted from an
* association procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-ASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_reassociate_indication - Report the establishment of an reassociation
* with a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* reassociation with a specific peer MAC entity that resulted from a
* reassociation procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*
* sta->previous_ap contains the "Current AP" information from ReassocReq.
*/
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-REASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_disassociate_indication - Report disassociation with a specific peer
* MAC entity
* @hapd: BSS data
* @sta: Peer STA data
* @reason_code: ReasonCode from Disassociation frame
*
* MLME calls this function as a result of the invalidation of an association
* relationship with a specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_disassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
mlme_deletekeys_request(hapd, sta);
}
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
const u8 *addr)
{
hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-MichaelMICFailure.indication(" MACSTR ")",
MAC2STR(addr));
}
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DELETEKEYS.request(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->wpa_sm)
wpa_remove_ptk(sta->wpa_sm);
}

40
hostapd/mlme.h Normal file
View File

@ -0,0 +1,40 @@
/*
* hostapd / IEEE 802.11 MLME
* Copyright 2003, Jouni Malinen <j@w1.fi>
* 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.
*/
#ifndef MLME_H
#define MLME_H
void mlme_authenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code);
void mlme_associate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_disassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code);
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
const u8 *addr);
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* MLME_H */

View File

@ -0,0 +1,52 @@
/*
* 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.
*/
#include "includes.h"
#include "common.h"
#include "ms_funcs.h"
int main(int argc, char *argv[])
{
unsigned char password_hash[16];
size_t i;
char *password, buf[64], *pos;
if (argc > 1)
password = argv[1];
else {
if (fgets(buf, sizeof(buf), stdin) == NULL) {
printf("Failed to read password\n");
return 1;
}
buf[sizeof(buf) - 1] = '\0';
pos = buf;
while (*pos != '\0') {
if (*pos == '\r' || *pos == '\n') {
*pos = '\0';
break;
}
pos++;
}
password = buf;
}
nt_password_hash((u8 *) password, strlen(password), password_hash);
for (i = 0; i < sizeof(password_hash); i++)
printf("%02x", password_hash[i]);
printf("\n");
return 0;
}

402
hostapd/peerkey.c Normal file
View File

@ -0,0 +1,402 @@
/*
* hostapd - PeerKey for Direct Link Setup (DLS)
* Copyright (c) 2006-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.
*/
#include "includes.h"
#include "common.h"
#include "eloop.h"
#include "sha1.h"
#include "sha256.h"
#include "wpa.h"
#include "defs.h"
#include "wpa_auth_i.h"
#include "wpa_auth_ie.h"
#ifdef CONFIG_PEERKEY
static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
{
#if 0
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_stsl_negotiation *neg = timeout_ctx;
#endif
/* TODO: ? */
}
struct wpa_stsl_search {
const u8 *addr;
struct wpa_state_machine *sm;
};
static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
{
struct wpa_stsl_search *search = ctx;
if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
search->sm = sm;
return 1;
}
return 0;
}
static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, const u8 *peer,
u16 mui, u16 error_type)
{
u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
u8 *pos;
struct rsn_error_kde error;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK Error");
pos = kde;
if (peer) {
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
NULL, 0);
}
error.mui = host_to_be16(mui);
error.error_type = host_to_be16(error_type);
pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
(u8 *) &error, sizeof(error), NULL, 0);
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
NULL, NULL, kde, pos - kde, 0, 0, 0);
}
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 *buf, *pos;
size_t buf_len;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
return;
}
if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
kde.mac_addr_len < ETH_ALEN) {
wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
"SMK M1");
return;
}
/* Initiator = sm->addr; Peer = kde.mac_addr */
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
" aborted - STA not associated anymore",
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Initiator RSN IE */
os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
pos = buf + kde.rsn_ie_len;
/* Initiator MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
NULL, 0);
/* SMK M2:
* EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
* MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
*/
wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
"Sending SMK M2");
__wpa_send_eapol(wpa_auth, search.sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
os_free(buf);
}
static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_key *key,
struct wpa_eapol_ie_parse *kde,
const u8 *smk)
{
u8 *buf, *pos;
size_t buf_len;
u32 lifetime;
/* SMK M4:
* EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
* MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
* Lifetime KDE)
*/
buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
pos = buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Initiator MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
NULL, 0);
/* Initiator Nonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
NULL, 0);
/* SMK with PNonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
key->key_nonce, WPA_NONCE_LEN);
/* Lifetime */
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK M4");
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
os_free(buf);
}
static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_key *key,
struct wpa_eapol_ie_parse *kde,
const u8 *smk, const u8 *peer)
{
u8 *buf, *pos;
size_t buf_len;
u32 lifetime;
/* SMK M5:
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
* MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
* Lifetime KDE))
*/
buf_len = kde->rsn_ie_len +
2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
pos = buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Peer RSN IE */
os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
pos = buf + kde->rsn_ie_len;
/* Peer MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
/* PNonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
WPA_NONCE_LEN, NULL, 0);
/* SMK and INonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
kde->nonce, WPA_NONCE_LEN);
/* Lifetime */
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK M5");
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_SMK_MESSAGE,
NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
os_free(buf);
}
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
return;
}
if (kde.rsn_ie == NULL ||
kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
"Nonce KDE in SMK M3");
return;
}
/* Peer = sm->addr; Initiator = kde.mac_addr;
* Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
" aborted - STA not associated anymore",
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
if (os_get_random(smk, PMK_LEN)) {
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
return;
}
/* SMK = PRF-256(Random number, "SMK Derivation",
* AA || Time || INonce || PNonce)
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
pos = buf + ETH_ALEN;
wpa_get_ntp_timestamp(pos);
pos += 8;
os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
#ifdef CONFIG_IEEE80211W
sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
smk, PMK_LEN);
#else /* CONFIG_IEEE80211W */
sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
smk, PMK_LEN);
#endif /* CONFIG_IEEE80211W */
wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
/* Authenticator does not need SMK anymore and it is required to forget
* it. */
os_memset(smk, 0, sizeof(*smk));
}
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
struct rsn_error_kde error;
u16 mui, error_type;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
return;
}
if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
kde.error == NULL || kde.error_len < sizeof(error)) {
wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
"SMK Error");
return;
}
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
"associated for SMK Error message from " MACSTR,
MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
return;
}
os_memcpy(&error, kde.error, sizeof(error));
mui = be_to_host16(error.mui);
error_type = be_to_host16(error.error_type);
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"STA reported SMK Error: Peer " MACSTR
" MUI %d Error Type %d",
MAC2STR(kde.mac_addr), mui, error_type);
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
}
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg)
{
struct wpa_stsl_negotiation *pos, *prev;
if (wpa_auth == NULL)
return -1;
pos = wpa_auth->stsl_negotiations;
prev = NULL;
while (pos) {
if (pos == neg) {
if (prev)
prev->next = pos->next;
else
wpa_auth->stsl_negotiations = pos->next;
eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
os_free(pos);
return 0;
}
prev = pos;
pos = pos->next;
}
return -1;
}
#endif /* CONFIG_PEERKEY */

455
hostapd/pmksa_cache.c Normal file
View File

@ -0,0 +1,455 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* 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.
*/
#include "includes.h"
#include "common.h"
#include "ap.h"
#include "config.h"
#include "common.h"
#include "eloop.h"
#include "sha1.h"
#include "sha256.h"
#include "ieee802_1x.h"
#include "eapol_sm.h"
#include "pmksa_cache.h"
static const int pmksa_cache_max_entries = 1024;
static const int dot11RSNAConfigPMKLifetime = 43200;
struct rsn_pmksa_cache {
#define PMKID_HASH_SIZE 128
#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
struct rsn_pmksa_cache_entry *pmksa;
int pmksa_count;
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
void *ctx;
};
/**
* rsn_pmkid - Calculate PMK identifier
* @pmk: Pairwise master key
* @pmk_len: Length of pmk in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: Buffer for PMKID
* @use_sha256: Whether to use SHA256-based KDF
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
*/
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256)
{
char *title = "PMK Name";
const u8 *addr[3];
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
unsigned char hash[SHA256_MAC_LEN];
addr[0] = (u8 *) title;
addr[1] = aa;
addr[2] = spa;
#ifdef CONFIG_IEEE80211W
if (use_sha256)
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
os_memcpy(pmkid, hash, PMKID_LEN);
}
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
if (entry == NULL)
return;
os_free(entry->identity);
ieee802_1x_free_radius_class(&entry->radius_class);
os_free(entry);
}
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL) {
prev->hnext = pos->hnext;
} else {
pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
pos->hnext;
}
break;
}
prev = pos;
pos = pos->hnext;
}
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL)
prev->next = pos->next;
else
pmksa->pmksa = pos->next;
break;
}
prev = pos;
pos = pos->next;
}
_pmksa_cache_free_entry(entry);
}
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
struct os_time now;
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);
}
pmksa_cache_set_expiration(pmksa);
}
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct os_time now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
os_get_time(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
}
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (eapol == NULL)
return;
if (eapol->identity) {
entry->identity = os_malloc(eapol->identity_len);
if (entry->identity) {
entry->identity_len = eapol->identity_len;
os_memcpy(entry->identity, eapol->identity,
eapol->identity_len);
}
}
ieee802_1x_copy_radius_class(&entry->radius_class,
&eapol->radius_class);
entry->eap_type_authsrv = eapol->eap_type_authsrv;
entry->vlan_id = eapol->sta->vlan_id;
}
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
return;
if (entry->identity) {
os_free(eapol->identity);
eapol->identity = os_malloc(entry->identity_len);
if (eapol->identity) {
eapol->identity_len = entry->identity_len;
os_memcpy(eapol->identity, entry->identity,
entry->identity_len);
}
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
eapol->identity, eapol->identity_len);
}
ieee802_1x_free_radius_class(&eapol->radius_class);
ieee802_1x_copy_radius_class(&eapol->radius_class,
&entry->radius_class);
if (eapol->radius_class.attr) {
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
"PMKSA", (unsigned long) eapol->radius_class.count);
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
eapol->sta->vlan_id = entry->vlan_id;
}
static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos->expiration > entry->expiration)
break;
prev = pos;
pos = pos->next;
}
if (prev == NULL) {
entry->next = pmksa->pmksa;
pmksa->pmksa = entry;
} else {
entry->next = prev->next;
prev->next = entry;
}
entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
pmksa->pmksa_count++;
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);
}
/**
* pmksa_cache_add - Add a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @aa: Authenticator address
* @spa: Supplicant address
* @session_timeout: Session timeout
* @eapol: Pointer to EAPOL state machine data
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
*
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
* cache. If an old entry is already in the cache for the same Supplicant,
* this entry will be replaced with the new entry. PMKID will be calculated
* based on the PMK.
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_time now;
if (pmk_len > PMK_LEN)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
os_get_time(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
entry->expiration += session_timeout;
else
entry->expiration += dot11RSNAConfigPMKLifetime;
entry->akmp = akmp;
os_memcpy(entry->spa, spa, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, eapol);
/* Replace an old entry for the same STA (if found) with the new entry
*/
pos = pmksa_cache_get(pmksa, spa, NULL);
if (pos)
pmksa_cache_free_entry(pmksa, pos);
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
/* Remove the oldest entry to make room for the new entry */
wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
"entry (for " MACSTR ") to make room for new one",
MAC2STR(pmksa->pmksa->spa));
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
}
pmksa_cache_link_entry(pmksa, entry);
return entry;
}
struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
entry->pmk_len = old_entry->pmk_len;
entry->expiration = old_entry->expiration;
entry->akmp = old_entry->akmp;
os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
entry->opportunistic = 1;
if (old_entry->identity) {
entry->identity = os_malloc(old_entry->identity_len);
if (entry->identity) {
entry->identity_len = old_entry->identity_len;
os_memcpy(entry->identity, old_entry->identity,
old_entry->identity_len);
}
}
ieee802_1x_copy_radius_class(&entry->radius_class,
&old_entry->radius_class);
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
entry->vlan_id = old_entry->vlan_id;
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
return entry;
}
/**
* pmksa_cache_deinit - Free all entries in PMKSA cache
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
*/
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
{
struct rsn_pmksa_cache_entry *entry, *prev;
int i;
if (pmksa == NULL)
return;
entry = pmksa->pmksa;
while (entry) {
prev = entry;
entry = entry->next;
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
for (i = 0; i < PMKID_HASH_SIZE; i++)
pmksa->pmkid[i] = NULL;
os_free(pmksa);
}
/**
* pmksa_cache_get - Fetch a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @spa: Supplicant address or %NULL to match any
* @pmkid: PMKID or %NULL to match any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *spa, const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
if (pmkid)
entry = pmksa->pmkid[PMKID_HASH(pmkid)];
else
entry = pmksa->pmksa;
while (entry) {
if ((spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
return entry;
entry = pmkid ? entry->hnext : entry->next;
}
return NULL;
}
/**
* pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: PMKID
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*
* Use opportunistic key caching (OKC) to find a PMK for a supplicant.
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
u8 new_pmkid[PMKID_LEN];
entry = pmksa->pmksa;
while (entry) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
wpa_key_mgmt_sha256(entry->akmp));
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
/**
* pmksa_cache_init - Initialize PMKSA cache
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
* @ctx: Context pointer for free_cb function
* Returns: Pointer to PMKSA cache data or %NULL on failure
*/
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx), void *ctx)
{
struct rsn_pmksa_cache *pmksa;
pmksa = os_zalloc(sizeof(*pmksa));
if (pmksa) {
pmksa->free_cb = free_cb;
pmksa->ctx = ctx;
}
return pmksa;
}

62
hostapd/pmksa_cache.h Normal file
View File

@ -0,0 +1,62 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* 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.
*/
#ifndef PMKSA_CACHE_H
#define PMKSA_CACHE_H
/**
* struct rsn_pmksa_cache_entry - PMKSA cache entry
*/
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next, *hnext;
u8 pmkid[PMKID_LEN];
u8 pmk[PMK_LEN];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 spa[ETH_ALEN];
u8 *identity;
size_t identity_len;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
int vlan_id;
int opportunistic;
};
struct rsn_pmksa_cache;
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx), void *ctx);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *spa, const u8 *pmkid);
struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
const u8 *pmkid);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid);
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
#endif /* PMKSA_CACHE_H */

275
hostapd/preauth.c Normal file
View File

@ -0,0 +1,275 @@
/*
* 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.
*/
#include "includes.h"
#ifdef CONFIG_RSN_PREAUTH
#include "hostapd.h"
#include "l2_packet/l2_packet.h"
#include "ieee802_1x.h"
#include "eloop.h"
#include "sta_info.h"
#include "wpa_common.h"
#include "eapol_sm.h"
#include "wpa.h"
#include "preauth.h"
#ifndef ETH_P_PREAUTH
#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
#endif /* ETH_P_PREAUTH */
static const int dot11RSNAConfigPMKLifetime = 43200;
struct rsn_preauth_interface {
struct rsn_preauth_interface *next;
struct hostapd_data *hapd;
struct l2_packet_data *l2;
char *ifname;
int ifindex;
};
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
struct rsn_preauth_interface *piface = ctx;
struct hostapd_data *hapd = piface->hapd;
struct ieee802_1x_hdr *hdr;
struct sta_info *sta;
struct l2_ethhdr *ethhdr;
wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
"from interface '%s'", piface->ifname);
if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
"(len=%lu)", (unsigned long) len);
return;
}
ethhdr = (struct l2_ethhdr *) buf;
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
MACSTR, MAC2STR(ethhdr->h_dest));
return;
}
sta = ap_get_sta(hapd, ethhdr->h_source);
if (sta && (sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
"STA " MACSTR, MAC2STR(sta->addr));
return;
}
if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
sta = ap_sta_add(hapd, ethhdr->h_source);
if (sta == NULL)
return;
sta->flags = WLAN_STA_PREAUTH;
ieee802_1x_new_station(hapd, sta);
if (sta->eapol_sm == NULL) {
ap_free_sta(hapd, sta);
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
sta->eapol_sm->portValid = TRUE;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}
if (sta == NULL)
return;
sta->preauth_iface = piface;
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
len - sizeof(*ethhdr));
}
static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
{
struct rsn_preauth_interface *piface;
wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
piface = os_zalloc(sizeof(*piface));
if (piface == NULL)
return -1;
piface->hapd = hapd;
piface->ifname = os_strdup(ifname);
if (piface->ifname == NULL) {
goto fail1;
}
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
rsn_preauth_receive, piface, 1);
if (piface->l2 == NULL) {
wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
"to ETH_P_PREAUTH");
goto fail2;
}
piface->next = hapd->preauth_iface;
hapd->preauth_iface = piface;
return 0;
fail2:
os_free(piface->ifname);
fail1:
os_free(piface);
return -1;
}
void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
struct rsn_preauth_interface *piface, *prev;
piface = hapd->preauth_iface;
hapd->preauth_iface = NULL;
while (piface) {
prev = piface;
piface = piface->next;
l2_packet_deinit(prev->l2);
os_free(prev->ifname);
os_free(prev);
}
}
int rsn_preauth_iface_init(struct hostapd_data *hapd)
{
char *tmp, *start, *end;
if (hapd->conf->rsn_preauth_interfaces == NULL)
return 0;
tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
if (tmp == NULL)
return -1;
start = tmp;
for (;;) {
while (*start == ' ')
start++;
if (*start == '\0')
break;
end = os_strchr(start, ' ');
if (end)
*end = '\0';
if (rsn_preauth_iface_add(hapd, start)) {
rsn_preauth_iface_deinit(hapd);
return -1;
}
if (end)
start = end + 1;
else
break;
}
os_free(tmp);
return 0;
}
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
MACSTR, MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
}
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success)
{
const u8 *key;
size_t len;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_INFO, "pre-authentication %s",
success ? "succeeded" : "failed");
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (len > PMK_LEN)
len = PMK_LEN;
if (success && key) {
if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
sta->addr,
dot11RSNAConfigPMKLifetime,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
"added PMKSA cache entry (pre-auth)");
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
"failed to add PMKSA cache entry "
"(pre-auth)");
}
}
/*
* Finish STA entry removal from timeout in order to avoid freeing
* STA data before the caller has finished processing.
*/
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
}
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
{
struct rsn_preauth_interface *piface;
struct l2_ethhdr *ethhdr;
piface = hapd->preauth_iface;
while (piface) {
if (piface == sta->preauth_iface)
break;
piface = piface->next;
}
if (piface == NULL) {
wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
"interface for " MACSTR, MAC2STR(sta->addr));
return;
}
ethhdr = os_malloc(sizeof(*ethhdr) + len);
if (ethhdr == NULL)
return;
os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
ethhdr->h_proto = htons(ETH_P_PREAUTH);
os_memcpy(ethhdr + 1, buf, len);
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
sizeof(*ethhdr) + len) < 0) {
wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
"l2_packet_send\n");
}
os_free(ethhdr);
}
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
}
#endif /* CONFIG_RSN_PREAUTH */

58
hostapd/preauth.h Normal file
View File

@ -0,0 +1,58 @@
/*
* 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.
*/
#ifndef PREAUTH_H
#define PREAUTH_H
#ifdef CONFIG_RSN_PREAUTH
int rsn_preauth_iface_init(struct hostapd_data *hapd);
void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success);
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len);
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_RSN_PREAUTH */
static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
}
static inline void rsn_preauth_finished(struct hostapd_data *hapd,
struct sta_info *sta,
int success)
{
}
static inline void rsn_preauth_send(struct hostapd_data *hapd,
struct sta_info *sta,
u8 *buf, size_t len)
{
}
static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
#endif /* CONFIG_RSN_PREAUTH */
#endif /* PREAUTH_H */

177
hostapd/prism54.h Normal file
View File

@ -0,0 +1,177 @@
#ifndef PRISM54_H
#define PRISM54_H
struct ieee802_3_hdr_s {
unsigned char da[6];
unsigned char sa[6];
unsigned short type;
} __attribute__ ((packed));
typedef struct ieee802_3_hdr_s ieee802_3_hdr;
#define PIMOP_GET 0
#define PIMOP_SET 1
#define PIMOP_RESPONSE 2
#define PIMOP_ERROR 3
#define PIMOP_TRAP 4
struct pimdev_hdr_s {
int op;
unsigned long oid;
} __attribute__ ((packed));
typedef struct pimdev_hdr_s pimdev_hdr;
#define DOT11_OID_ATTACHMENT 0x19000003
/* really need to check */
#define DOT11_PKT_BEACON 0x80
#define DOT11_PKT_ASSOC_RESP 0x10
#define DOT11_PKT_REASSOC_RESP 0x30
#define DOT11_PKT_PROBE_RESP 0x50
struct obj_attachment_hdr {
char type;
char reserved;
short id;
short size;
} __attribute__ ((packed));
struct obj_attachment {
char type;
char reserved;
short id;
short size;
char data[1];
} __attribute__ ((packed));
#define DOT11_OID_MLMEAUTOLEVEL 0x19000001
#define DOT11_MLME_AUTO 0
#define DOT11_MLME_INTERMEDIATE 0x01000000
#define DOT11_MLME_EXTENDED 0x02000000
#define DOT11_OID_DEAUTHENTICATE 0x18000000
#define DOT11_OID_AUTHENTICATE 0x18000001
#define DOT11_OID_DISASSOCIATE 0x18000002
#define DOT11_OID_ASSOCIATE 0x18000003
#define DOT11_OID_BEACON 0x18000005
#define DOT11_OID_PROBE 0x18000006
#define DOT11_OID_REASSOCIATE 0x1800000b
struct obj_mlme {
char address[6];
short id;
short state;
short code;
} __attribute__ ((packed));
#define DOT11_OID_DEAUTHENTICATEEX 0x18000007
#define DOT11_OID_AUTHENTICATEEX 0x18000008
#define DOT11_OID_DISASSOCIATEEX 0x18000009
#define DOT11_OID_ASSOCIATEEX 0x1800000a
#define DOT11_OID_REASSOCIATEEX 0x1800000c
struct obj_mlmeex {
char address[6];
short id;
short state;
short code;
short size;
char data[1];
} __attribute__ ((packed));
#define DOT11_OID_STAKEY 0x12000008
#define DOT11_PRIV_WEP 0
#define DOT11_PRIV_TKIP 1
/* endian reversed to bigger endian */
#define DOT11_STAKEY_OPTION_DEFAULTKEY 0x100
struct obj_stakey {
char address[6];
char keyid;
char reserved;
short options;
char type;
char length;
char key[32];
} __attribute__ ((packed));
#define DOT11_OID_DEFKEYID 0x12000003
#define DOT11_OID_DEFKEY1 0x12000004
#define DOT11_OID_DEFKEY2 0x12000005
#define DOT11_OID_DEFKEY3 0x12000006
#define DOT11_OID_DEFKEY4 0x12000007
struct obj_key {
char type;
char length;
char key[32];
} __attribute__ ((packed));
#define DOT11_OID_STASC 0x1200000a
struct obj_stasc {
char address[6];
char keyid;
char tx_sc;
unsigned long sc_high;
unsigned short sc_low;
} __attribute__ ((packed));
#define DOT11_OID_CLIENTS 0x15000001
#define DOT11_OID_CLIENTSASSOCIATED 0x15000002
#define DOT11_OID_CLIENTST 0x15000003
#define DOT11_OID_CLIENTEND 0x150007d9
#define DOT11_OID_CLIENTFIND 0x150007db
#define DOT11_NODE_UNKNOWN
#define DOT11_NODE_CLIENT
#define DOT11_NODE_AP
/* endian reversed to bigger endian */
#define DOT11_STATE_NONE 0
#define DOT11_STATE_AUTHING 0x100
#define DOT11_STATE_AUTH 0x200
#define DOT11_STATE_ASSOCING 0x300
#define DOT11_STATE_REASSOCING 0x400
#define DOT11_STATE_ASSOC 0x500
#define DOT11_STATE_WDS 0x600
struct obj_sta {
char address[6];
char pad[2];
char state;
char node;
short age;
char reserved1;
char rssi;
char rate;
char reserved2;
} __attribute__ ((packed));
#define DOT11_OID_SSID 0x10000002
#define DOT11_OID_SSIDOVERRIDE 0x10000006
struct obj_ssid {
char length;
char octets[33];
} __attribute__ ((packed));
#define DOT11_OID_EAPAUTHSTA 0x150007de
#define DOT11_OID_EAPUNAUTHSTA 0x150007df
/* not in 38801 datasheet??? */
#define DOT11_OID_DOT1XENABLE 0x150007e0
#define DOT11_OID_MICFAILURE 0x150007e1
#define DOT11_OID_AUTHENABLE 0x12000000
#define DOT11_OID_PRIVACYINVOKED 0x12000001
#define DOT11_OID_EXUNENCRYPTED 0x12000002
#define DOT11_AUTH_OS 0x01000000
#define DOT11_AUTH_SK 0x02000000
#define DOT11_AUTH_BOTH 0x03000000
#define DOT11_BOOL_TRUE 0x01000000
#endif /* PRISM54_H */

71
hostapd/priv_netlink.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef PRIV_NETLINK_H
#define PRIV_NETLINK_H
/* Private copy of needed Linux netlink/rtnetlink definitions.
*
* This should be replaced with user space header once one is available with C
* library, etc..
*/
#ifndef IFLA_IFNAME
#define IFLA_IFNAME 3
#endif
#ifndef IFLA_WIRELESS
#define IFLA_WIRELESS 11
#endif
#define NETLINK_ROUTE 0
#define RTMGRP_LINK 1
#define RTM_BASE 0x10
#define RTM_NEWLINK (RTM_BASE + 0)
#define RTM_DELLINK (RTM_BASE + 1)
#define NLMSG_ALIGNTO 4
#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
#define RTA_ALIGNTO 4
#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
#define RTA_OK(rta,len) \
((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
(rta)->rta_len <= (len))
#define RTA_NEXT(rta,attrlen) \
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
struct sockaddr_nl
{
sa_family_t nl_family;
unsigned short nl_pad;
u32 nl_pid;
u32 nl_groups;
};
struct nlmsghdr
{
u32 nlmsg_len;
u16 nlmsg_type;
u16 nlmsg_flags;
u32 nlmsg_seq;
u32 nlmsg_pid;
};
struct ifinfomsg
{
unsigned char ifi_family;
unsigned char __ifi_pad;
unsigned short ifi_type;
int ifi_index;
unsigned ifi_flags;
unsigned ifi_change;
};
struct rtattr
{
unsigned short rta_len;
unsigned short rta_type;
};
#endif /* PRIV_NETLINK_H */

287
hostapd/radiotap.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Radiotap parser
*
* Copyright 2007 Andy Green <andy@warmcat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
*
* Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
* I only modified some things on top to ease syncing should bugs be found.
*/
#include "includes.h"
#include "common.h"
#include "radiotap_iter.h"
#define le16_to_cpu le_to_host16
#define le32_to_cpu le_to_host32
#define __le32 uint32_t
#define ulong unsigned long
#define unlikely(cond) (cond)
#define get_unaligned(p) \
({ \
struct packed_dummy_struct { \
typeof(*(p)) __val; \
} __attribute__((packed)) *__ptr = (void *) (p); \
\
__ptr->__val; \
})
/* function prototypes and related defs are in radiotap_iter.h */
/**
* ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
* @iterator: radiotap_iterator to initialize
* @radiotap_header: radiotap header to parse
* @max_length: total length we can parse into (eg, whole packet length)
*
* Returns: 0 or a negative error code if there is a problem.
*
* This function initializes an opaque iterator struct which can then
* be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
* argument which is present in the header. It knows about extended
* present headers and handles them.
*
* How to use:
* call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
* struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
* checking for a good 0 return code. Then loop calling
* __ieee80211_radiotap_iterator_next()... it returns either 0,
* -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
* The iterator's @this_arg member points to the start of the argument
* associated with the current argument index that is present, which can be
* found in the iterator's @this_arg_index member. This arg index corresponds
* to the IEEE80211_RADIOTAP_... defines.
*
* Radiotap header length:
* You can find the CPU-endian total radiotap header length in
* iterator->max_length after executing ieee80211_radiotap_iterator_init()
* successfully.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
* for multibyte types... the pointer is not aligned. Use
* get_unaligned((type *)iterator.this_arg) to dereference
* iterator.this_arg for type "type" safely on all arches.
*
* Example code:
* See Documentation/networking/radiotap-headers.txt
*/
int ieee80211_radiotap_iterator_init(
struct ieee80211_radiotap_iterator *iterator,
struct ieee80211_radiotap_header *radiotap_header,
int max_length)
{
/* Linux only supports version 0 radiotap format */
if (radiotap_header->it_version)
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
return -EINVAL;
iterator->rtheader = radiotap_header;
iterator->max_length = le16_to_cpu(get_unaligned(
&radiotap_header->it_len));
iterator->arg_index = 0;
iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
&radiotap_header->it_present));
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
iterator->this_arg = NULL;
/* find payload start allowing for extended bitmap(s) */
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
(1<<IEEE80211_RADIOTAP_EXT)) {
iterator->arg += sizeof(u32);
/*
* check for insanity where the present bitmaps
* keep claiming to extend up to or even beyond the
* stated radiotap header length
*/
if (((ulong)iterator->arg - (ulong)iterator->rtheader)
> (ulong)iterator->max_length)
return -EINVAL;
}
iterator->arg += sizeof(u32);
/*
* no need to check again for blowing past stated radiotap
* header length, because ieee80211_radiotap_iterator_next
* checks it before it is dereferenced
*/
}
/* we are all initialized happily */
return 0;
}
/**
* ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
* @iterator: radiotap_iterator to move to next arg (if any)
*
* Returns: 0 if there is an argument to handle,
* -ENOENT if there are no more args or -EINVAL
* if there is something else wrong.
*
* This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
* in @this_arg_index and sets @this_arg to point to the
* payload for the field. It takes care of alignment handling and extended
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
* little-endian format whatever the endianess of your CPU.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
* for multibyte types... the pointer is not aligned. Use
* get_unaligned((type *)iterator.this_arg) to dereference
* iterator.this_arg for type "type" safely on all arches.
*/
int ieee80211_radiotap_iterator_next(
struct ieee80211_radiotap_iterator *iterator)
{
/*
* small length lookup table for all radiotap types we heard of
* starting from b0 in the bitmap, so we can walk the payload
* area of the radiotap header
*
* There is a requirement to pad args, so that args
* of a given length must begin at a boundary of that length
* -- but note that compound args are allowed (eg, 2 x u16
* for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
* a reliable indicator of alignment requirement.
*
* upper nybble: content alignment for arg
* lower nybble: content length for arg
*/
static const u8 rt_sizes[] = {
[IEEE80211_RADIOTAP_TSFT] = 0x88,
[IEEE80211_RADIOTAP_FLAGS] = 0x11,
[IEEE80211_RADIOTAP_RATE] = 0x11,
[IEEE80211_RADIOTAP_CHANNEL] = 0x24,
[IEEE80211_RADIOTAP_FHSS] = 0x22,
[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
[IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
[IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
[IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
[IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
[IEEE80211_RADIOTAP_ANTENNA] = 0x11,
[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
[IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
[IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
[IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
[IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
[IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
/*
* add more here as they are defined in
* include/net/ieee80211_radiotap.h
*/
};
/*
* for every radiotap entry we can at
* least skip (by knowing the length)...
*/
while (iterator->arg_index < (int) sizeof(rt_sizes)) {
int hit = 0;
int pad;
if (!(iterator->bitmap_shifter & 1))
goto next_entry; /* arg not present */
/*
* arg is present, account for alignment padding
* 8-bit args can be at any alignment
* 16-bit args must start on 16-bit boundary
* 32-bit args must start on 32-bit boundary
* 64-bit args must start on 64-bit boundary
*
* note that total arg size can differ from alignment of
* elements inside arg, so we use upper nybble of length
* table to base alignment on
*
* also note: these alignments are ** relative to the
* start of the radiotap header **. There is no guarantee
* that the radiotap header itself is aligned on any
* kind of boundary.
*
* the above is why get_unaligned() is used to dereference
* multibyte elements from the radiotap area
*/
pad = (((ulong)iterator->arg) -
((ulong)iterator->rtheader)) &
((rt_sizes[iterator->arg_index] >> 4) - 1);
if (pad)
iterator->arg +=
(rt_sizes[iterator->arg_index] >> 4) - pad;
/*
* this is what we will return to user, but we need to
* move on first so next call has something fresh to test
*/
iterator->this_arg_index = iterator->arg_index;
iterator->this_arg = iterator->arg;
hit = 1;
/* internally move on the size of this arg */
iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
/*
* check for insanity where we are given a bitmap that
* claims to have more arg content than the length of the
* radiotap section. We will normally end up equalling this
* max_length on the last arg, never exceeding it.
*/
if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
(ulong) iterator->max_length)
return -EINVAL;
next_entry:
iterator->arg_index++;
if (unlikely((iterator->arg_index & 31) == 0)) {
/* completed current u32 bitmap */
if (iterator->bitmap_shifter & 1) {
/* b31 was set, there is more */
/* move to next u32 bitmap */
iterator->bitmap_shifter = le32_to_cpu(
get_unaligned(iterator->next_bitmap));
iterator->next_bitmap++;
} else
/* no more bitmaps: end */
iterator->arg_index = sizeof(rt_sizes);
} else /* just try the next bit */
iterator->bitmap_shifter >>= 1;
/* if we found a valid arg earlier, return it now */
if (hit)
return 0;
}
/* we don't know how to handle any more args, we're done */
return -ENOENT;
}

242
hostapd/radiotap.h Normal file
View File

@ -0,0 +1,242 @@
/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
/*-
* Copyright (c) 2003, 2004 David Young. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of David Young may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``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 DAVID
* YOUNG 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.
*/
/*
* Modifications to fit into the linux IEEE 802.11 stack,
* Mike Kershaw (dragorn@kismetwireless.net)
*/
#ifndef IEEE80211RADIOTAP_H
#define IEEE80211RADIOTAP_H
#include <stdint.h>
/* Base version of the radiotap packet header data */
#define PKTHDR_RADIOTAP_VERSION 0
/* A generic radio capture format is desirable. There is one for
* Linux, but it is neither rigidly defined (there were not even
* units given for some fields) nor easily extensible.
*
* I suggest the following extensible radio capture format. It is
* based on a bitmap indicating which fields are present.
*
* I am trying to describe precisely what the application programmer
* should expect in the following, and for that reason I tell the
* units and origin of each measurement (where it applies), or else I
* use sufficiently weaselly language ("is a monotonically nondecreasing
* function of...") that I cannot set false expectations for lawyerly
* readers.
*/
/* The radio capture header precedes the 802.11 header.
* All data in the header is little endian on all platforms.
*/
struct ieee80211_radiotap_header {
uint8_t it_version; /* Version 0. Only increases
* for drastic changes,
* introduction of compatible
* new fields does not count.
*/
uint8_t it_pad;
uint16_t it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
uint32_t it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
* Additional extensions are made
* by setting bit 31.
*/
};
/* Name Data type Units
* ---- --------- -----
*
* IEEE80211_RADIOTAP_TSFT __le64 microseconds
*
* Value in microseconds of the MAC's 64-bit 802.11 Time
* Synchronization Function timer when the first bit of the
* MPDU arrived at the MAC. For received frames, only.
*
* IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
*
* Tx/Rx frequency in MHz, followed by flags (see below).
*
* IEEE80211_RADIOTAP_FHSS uint16_t see below
*
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
* IEEE80211_RADIOTAP_RATE u8 500kb/s
*
* Tx/Rx data rate
*
* IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
* one milliwatt (dBm)
*
* RF signal power at the antenna, decibel difference from
* one milliwatt.
*
* IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
* one milliwatt (dBm)
*
* RF noise power at the antenna, decibel difference from one
* milliwatt.
*
* IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
*
* RF signal power at the antenna, decibel difference from an
* arbitrary, fixed reference.
*
* IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
*
* RF noise power at the antenna, decibel difference from an
* arbitrary, fixed reference point.
*
* IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
*
* Quality of Barker code lock. Unitless. Monotonically
* nondecreasing with "better" lock strength. Called "Signal
* Quality" in datasheets. (Is there a standard way to measure
* this?)
*
* IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
*
* Transmit power expressed as unitless distance from max
* power set at factory calibration. 0 is max power.
* Monotonically nondecreasing with lower power levels.
*
* IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
*
* Transmit power expressed as decibel distance from max power
* set at factory calibration. 0 is max power. Monotonically
* nondecreasing with lower power levels.
*
* IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
* one milliwatt (dBm)
*
* Transmit power expressed as dBm (decibels from a 1 milliwatt
* reference). This is the absolute power level measured at
* the antenna port.
*
* IEEE80211_RADIOTAP_FLAGS u8 bitmap
*
* Properties of transmitted and received frames. See flags
* defined below.
*
* IEEE80211_RADIOTAP_ANTENNA u8 antenna index
*
* Unitless indication of the Rx/Tx antenna for this packet.
* The first antenna is antenna 0.
*
* IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
*
* Properties of received frames. See flags defined below.
*
* IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
*
* Properties of transmitted frames. See flags defined below.
*
* IEEE80211_RADIOTAP_RTS_RETRIES u8 data
*
* Number of rts retries a transmitted frame used.
*
* IEEE80211_RADIOTAP_DATA_RETRIES u8 data
*
* Number of unicast retries a transmitted frame used.
*
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_FLAGS = 1,
IEEE80211_RADIOTAP_RATE = 2,
IEEE80211_RADIOTAP_CHANNEL = 3,
IEEE80211_RADIOTAP_FHSS = 4,
IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
IEEE80211_RADIOTAP_RX_FLAGS = 14,
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
IEEE80211_RADIOTAP_EXT = 31
};
/* Channel flags. */
#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
/* For IEEE80211_RADIOTAP_FLAGS */
#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
* during CFP
*/
#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
* with short
* preamble
*/
#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
* with WEP encryption
*/
#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
* with fragmentation
*/
#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
* 802.11 header and payload
* (to 32-bit boundary)
*/
/* For IEEE80211_RADIOTAP_RX_FLAGS */
#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
/* For IEEE80211_RADIOTAP_TX_FLAGS */
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
* retries */
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#endif /* IEEE80211_RADIOTAP_H */

41
hostapd/radiotap_iter.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef __RADIOTAP_ITER_H
#define __RADIOTAP_ITER_H
#include "radiotap.h"
/* Radiotap header iteration
* implemented in radiotap.c
*/
/**
* struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
* @rtheader: pointer to the radiotap header we are walking through
* @max_length: length of radiotap header in cpu byte ordering
* @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
* @this_arg: pointer to current radiotap arg
* @arg_index: internal next argument index
* @arg: internal next argument pointer
* @next_bitmap: internal pointer to next present u32
* @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
*/
struct ieee80211_radiotap_iterator {
struct ieee80211_radiotap_header *rtheader;
int max_length;
int this_arg_index;
unsigned char *this_arg;
int arg_index;
unsigned char *arg;
uint32_t *next_bitmap;
uint32_t bitmap_shifter;
};
extern int ieee80211_radiotap_iterator_init(
struct ieee80211_radiotap_iterator *iterator,
struct ieee80211_radiotap_header *radiotap_header,
int max_length);
extern int ieee80211_radiotap_iterator_next(
struct ieee80211_radiotap_iterator *iterator);
#endif /* __RADIOTAP_ITER_H */

711
hostapd/sta_info.c Normal file
View File

@ -0,0 +1,711 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2008, 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "sta_info.h"
#include "eloop.h"
#include "accounting.h"
#include "ieee802_1x.h"
#include "ieee802_11.h"
#include "radius/radius.h"
#include "wpa.h"
#include "preauth.h"
#include "radius/radius_client.h"
#include "driver.h"
#include "beacon.h"
#include "hw_features.h"
#include "mlme.h"
#include "vlan_init.h"
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta, u32 flags);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
void *ctx)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (cb(hapd, sta, ctx))
return 1;
}
return 0;
}
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
{
struct sta_info *s;
s = hapd->sta_hash[STA_HASH(sta)];
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
s = s->hnext;
return s;
}
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *tmp;
if (hapd->sta_list == sta) {
hapd->sta_list = sta->next;
return;
}
tmp = hapd->sta_list;
while (tmp != NULL && tmp->next != sta)
tmp = tmp->next;
if (tmp == NULL) {
wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
"list.", MAC2STR(sta->addr));
} else
tmp->next = sta->next;
}
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
{
sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
hapd->sta_hash[STA_HASH(sta->addr)] = sta;
}
static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *s;
s = hapd->sta_hash[STA_HASH(sta->addr)];
if (s == NULL) return;
if (os_memcmp(s->addr, sta->addr, 6) == 0) {
hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
return;
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
" from hash table", MAC2STR(sta->addr));
}
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
accounting_sta_stop(hapd, sta);
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
if (sta->aid > 0)
hapd->sta_aid[sta->aid - 1] = NULL;
hapd->num_sta--;
if (sta->nonerp_set) {
sta->nonerp_set = 0;
hapd->iface->num_sta_non_erp--;
if (hapd->iface->num_sta_non_erp == 0)
set_beacon++;
}
if (sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 0;
hapd->iface->num_sta_no_short_slot_time--;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_slot_time == 0)
set_beacon++;
}
if (sta->no_short_preamble_set) {
sta->no_short_preamble_set = 0;
hapd->iface->num_sta_no_short_preamble--;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 0)
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (sta->no_ht_gf_set) {
sta->no_ht_gf_set = 0;
hapd->iface->num_sta_ht_no_gf--;
}
if (sta->no_ht_set) {
sta->no_ht_set = 0;
hapd->iface->num_sta_no_ht--;
}
if (sta->ht_20mhz_set) {
sta->ht_20mhz_set = 0;
hapd->iface->num_sta_ht_20mhz--;
}
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
radius_client_flush_auth(hapd->radius, sta->addr);
os_free(sta->last_assoc_req);
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
#endif /* CONFIG_IEEE80211W */
wpabuf_free(sta->wps_ie);
os_free(sta);
}
void hostapd_free_stas(struct hostapd_data *hapd)
{
struct sta_info *sta, *prev;
sta = hapd->sta_list;
while (sta) {
prev = sta;
if (sta->flags & WLAN_STA_AUTH) {
mlme_deauthenticate_indication(
hapd, sta, WLAN_REASON_UNSPECIFIED);
}
sta = sta->next;
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
MAC2STR(prev->addr));
ap_free_sta(hapd, prev);
}
}
/**
* ap_handle_timer - Per STA timer handler
* @eloop_ctx: struct hostapd_data *
* @timeout_ctx: struct sta_info *
*
* This function is called to check station activity and to remove inactive
* stations.
*/
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"local deauth request");
ap_free_sta(hapd, sta);
return;
}
if ((sta->flags & WLAN_STA_ASSOC) &&
(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 = hostapd_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));
} 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");
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity -
inactive_sec;
}
}
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");
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity;
}
if (next_time) {
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
sta);
return;
}
if (sta->timeout_next == STA_NULLFUNC &&
(sta->flags & WLAN_STA_ASSOC)) {
/* 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");
sta->flags |= WLAN_STA_PENDING_POLL;
#ifndef CONFIG_NATIVE_WINDOWS
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 (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
perror("ap_handle_timer: send");
#endif /* CONFIG_NATIVE_WINDOWS */
} 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));
if (deauth) {
hostapd_sta_deauth(hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
} else {
hostapd_sta_disassoc(
hapd, sta->addr,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
}
}
switch (sta->timeout_next) {
case STA_NULLFUNC:
sta->timeout_next = STA_DISASSOC;
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
hapd, sta);
break;
case STA_DISASSOC:
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
sta->timeout_next = STA_DEAUTH;
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
break;
case STA_DEAUTH:
case STA_REMOVE:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"inactivity");
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
mlme_deauthenticate_indication(
hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
ap_free_sta(hapd, sta);
break;
}
}
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH))
return;
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"session timeout");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
}
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
"seconds", session_timeout);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
hapd, sta);
}
void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
}
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
if (sta)
return sta;
wpa_printf(MSG_DEBUG, " New STA");
if (hapd->num_sta >= hapd->conf->max_num_sta) {
/* FIX: might try to remove some old STAs first? */
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
hapd->num_sta, hapd->conf->max_num_sta);
return NULL;
}
sta = os_zalloc(sizeof(struct sta_info));
if (sta == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
return NULL;
}
sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
/* initialize STA info data */
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
sta->next = hapd->sta_list;
hapd->sta_list = sta;
hapd->num_sta++;
ap_sta_hash_add(hapd, sta);
sta->ssid = &hapd->conf->ssid;
return sta;
}
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
MAC2STR(sta->addr));
if (hostapd_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));
return -1;
}
return 0;
}
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta, u32 flags)
{
struct hostapd_iface *iface = hapd->iface;
size_t i;
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
struct sta_info *sta2;
/* bss should always be set during operation, but it may be
* NULL during reconfiguration. Assume the STA is not
* associated to another BSS in that case to avoid NULL pointer
* dereferences. */
if (bss == hapd || bss == NULL)
continue;
sta2 = ap_get_sta(bss, sta->addr);
if (sta2 && ((sta2->flags & flags) == flags))
return 1;
}
return 0;
}
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;
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
ap_sta_remove(hapd, sta);
sta->timeout_next = STA_DEAUTH;
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);
}
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
ap_sta_remove(hapd, sta);
sta->timeout_next = STA_REMOVE;
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);
}
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
const char *iface;
struct hostapd_vlan *vlan = NULL;
/*
* Do not proceed furthur if the vlan id remains same. We do not want
* duplicate dynamic vlan entries.
*/
if (sta->vlan_id == old_vlanid)
return 0;
/*
* During 1x reauth, if the vlan id changes, then remove the old id and
* proceed furthur to add the new one.
*/
if (old_vlanid > 0)
vlan_remove_dynamic(hapd, old_vlanid);
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
iface = sta->ssid->vlan;
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
vlan = hapd->conf->vlan;
while (vlan) {
if (vlan->vlan_id == sta->vlan_id ||
vlan->vlan_id == VLAN_ID_WILDCARD) {
iface = vlan->ifname;
break;
}
vlan = vlan->next;
}
}
if (sta->vlan_id > 0 && vlan == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
sta->vlan_id);
return -1;
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
if (vlan == NULL) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not add "
"dynamic VLAN interface for vlan_id=%d",
sta->vlan_id);
return -1;
}
iface = vlan->ifname;
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
"configure encryption for dynamic VLAN "
"interface for vlan_id=%d",
sta->vlan_id);
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
"interface '%s'", iface);
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
if (sta->vlan_id > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "updated existing "
"dynamic VLAN interface '%s'", iface);
}
/*
* Update encryption configuration for statically generated
* VLAN interface. This is only used for static WEP
* configuration for the case where hostapd did not yet know
* which keys are to be used when the interface was added.
*/
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
"configure encryption for VLAN "
"interface for vlan_id=%d",
sta->vlan_id);
}
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
}
#ifdef CONFIG_IEEE80211W
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
struct os_time now, passed;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"association SA Query timed out");
sta->sa_query_timed_out = 1;
os_free(sta->sa_query_trans_id);
sta->sa_query_trans_id = NULL;
sta->sa_query_count = 0;
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
return 1;
}
return 0;
}
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned int timeout, sec, usec;
u8 *trans_id, *nbuf;
if (sta->sa_query_count > 0 &&
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);
if (nbuf == NULL)
return;
if (sta->sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_time(&sta->sa_query_start);
}
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
timeout = hapd->conf->assoc_sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
usec = (timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
}
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
{
ap_sa_query_timer(hapd, sta);
}
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
os_free(sta->sa_query_trans_id);
sta->sa_query_trans_id = NULL;
sta->sa_query_count = 0;
}
#endif /* CONFIG_IEEE80211W */

43
hostapd/sta_info.h Normal file
View File

@ -0,0 +1,43 @@
/*
* hostapd / Station table
* Copyright (c) 2002-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.
*/
#ifndef STA_INFO_H
#define STA_INFO_H
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
void *ctx);
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,
u32 session_timeout);
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
struct sta_info *sta);
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
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);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */

826
hostapd/vlan_init.c Normal file
View File

@ -0,0 +1,826 @@
/*
* hostapd / VLAN initialization
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "hostapd.h"
#include "driver.h"
#include "vlan_init.h"
#ifdef CONFIG_FULL_DYNAMIC_VLAN
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/if_vlan.h>
#include <linux/if_bridge.h>
#include "priv_netlink.h"
#include "eloop.h"
struct full_dynamic_vlan {
int s; /* socket on which to listen for new/removed interfaces. */
};
static int ifconfig_helper(const char *if_name, int up)
{
int fd;
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
perror("ioctl[SIOCGIFFLAGS]");
close(fd);
return -1;
}
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
perror("ioctl[SIOCSIFFLAGS]");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int ifconfig_up(const char *if_name)
{
return ifconfig_helper(if_name, 1);
}
static int ifconfig_down(const char *if_name)
{
return ifconfig_helper(if_name, 0);
}
/*
* These are only available in recent linux headers (without the leading
* underscore).
*/
#define _GET_VLAN_REALDEV_NAME_CMD 8
#define _GET_VLAN_VID_CMD 9
/* This value should be 256 ONLY. If it is something else, then hostapd
* might crash!, as this value has been hard-coded in 2.4.x kernel
* bridging code.
*/
#define MAX_BR_PORTS 256
static int br_delif(const char *br_name, const char *if_name)
{
int fd;
struct ifreq ifr;
unsigned long args[2];
int if_index;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
if_index = if_nametoindex(if_name);
if (if_index == 0) {
printf("Failure determining interface index for '%s'\n",
if_name);
close(fd);
return -1;
}
args[0] = BRCTL_DEL_IF;
args[1] = if_index;
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) args;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
/* No error if interface already removed. */
perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add interface 'if_name' to the bridge 'br_name'
returns -1 on error
returns 1 if the interface is already part of the bridge
returns 0 otherwise
*/
static int br_addif(const char *br_name, const char *if_name)
{
int fd;
struct ifreq ifr;
unsigned long args[2];
int if_index;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
if_index = if_nametoindex(if_name);
if (if_index == 0) {
printf("Failure determining interface index for '%s'\n",
if_name);
close(fd);
return -1;
}
args[0] = BRCTL_ADD_IF;
args[1] = if_index;
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) args;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
if (errno == EBUSY) {
/* The interface is already added. */
close(fd);
return 1;
}
perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int br_delbr(const char *br_name)
{
int fd;
unsigned long arg[2];
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
arg[0] = BRCTL_DEL_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
/* No error if bridge already removed. */
perror("ioctl[BRCTL_DEL_BRIDGE]");
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add a bridge with the name 'br_name'.
returns -1 on error
returns 1 if the bridge already exists
returns 0 otherwise
*/
static int br_addbr(const char *br_name)
{
int fd;
unsigned long arg[2];
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
arg[0] = BRCTL_ADD_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
if (errno == EEXIST) {
/* The bridge is already added. */
close(fd);
return 1;
} else {
perror("ioctl[BRCTL_ADD_BRIDGE]");
close(fd);
return -1;
}
}
close(fd);
return 0;
}
static int br_getnumports(const char *br_name)
{
int fd;
int i;
int port_cnt = 0;
unsigned long arg[4];
int ifindices[MAX_BR_PORTS];
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
arg[0] = BRCTL_GET_PORT_LIST;
arg[1] = (unsigned long) ifindices;
arg[2] = MAX_BR_PORTS;
arg[3] = 0;
os_memset(ifindices, 0, sizeof(ifindices));
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) arg;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
close(fd);
return -1;
}
for (i = 1; i < MAX_BR_PORTS; i++) {
if (ifindices[i] > 0) {
port_cnt++;
}
}
close(fd);
return port_cnt;
}
static int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
fprintf(stderr, "Interface name to long.\n");
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.cmd = DEL_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add a vlan interface with VLAN ID 'vid' and tagged interface
'if_name'.
returns -1 on error
returns 1 if the interface already exists
returns 0 otherwise
*/
static int vlan_add(const char *if_name, int vid)
{
int fd;
struct vlan_ioctl_args if_request;
ifconfig_up(if_name);
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
fprintf(stderr, "Interface name to long.\n");
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
/* Determine if a suitable vlan device already exists. */
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
vid);
if_request.cmd = _GET_VLAN_VID_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
if (if_request.u.VID == vid) {
if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
os_strncmp(if_request.u.device2, if_name,
sizeof(if_request.u.device2)) == 0) {
close(fd);
return 1;
}
}
}
/* A suitable vlan device does not already exist, add one. */
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.u.VID = vid;
if_request.cmd = ADD_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
close(fd);
return -1;
}
close(fd);
return 0;
}
static int vlan_set_name_type(unsigned int name_type)
{
int fd;
struct vlan_ioctl_args if_request;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket[AF_INET,SOCK_STREAM]");
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
if_request.u.name_type = name_type;
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
close(fd);
return -1;
}
close(fd);
return 0;
}
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
ifconfig_up(br_name);
if (tagged_interface) {
if (!vlan_add(tagged_interface, vlan->vlan_id))
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;
ifconfig_up(vlan_ifname);
}
if (!br_addif(br_name, ifname))
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
ifconfig_up(ifname);
break;
}
vlan = vlan->next;
}
}
static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
char br_name[IFNAMSIZ];
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int numports;
first = prev = vlan;
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (tagged_interface) {
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
numports = br_getnumports(br_name);
if (numports == 1) {
br_delif(br_name, vlan_ifname);
vlan_rem(vlan_ifname);
ifconfig_down(br_name);
br_delbr(br_name);
}
}
if (vlan == first) {
hapd->conf->vlan = vlan->next;
} else {
prev->next = vlan->next;
}
os_free(vlan);
break;
}
prev = vlan;
vlan = vlan->next;
}
}
static void
vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
struct hostapd_data *hapd)
{
struct ifinfomsg *ifi;
int attrlen, nlmsg_len, rta_len;
struct rtattr *attr;
if (len < sizeof(*ifi))
return;
ifi = NLMSG_DATA(h);
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
attrlen = h->nlmsg_len - nlmsg_len;
if (attrlen < 0)
return;
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
char ifname[IFNAMSIZ + 1];
if (attr->rta_type == IFLA_IFNAME) {
int n = attr->rta_len - rta_len;
if (n < 0)
break;
os_memset(ifname, 0, sizeof(ifname));
if ((size_t) n > sizeof(ifname))
n = sizeof(ifname);
os_memcpy(ifname, ((char *) attr) + rta_len, n);
if (del)
vlan_dellink(ifname, hapd);
else
vlan_newlink(ifname, hapd);
}
attr = RTA_NEXT(attr, attrlen);
}
}
static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
char buf[8192];
int left;
struct sockaddr_nl from;
socklen_t fromlen;
struct nlmsghdr *h;
struct hostapd_data *hapd = eloop_ctx;
fromlen = sizeof(from);
left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
(struct sockaddr *) &from, &fromlen);
if (left < 0) {
if (errno != EINTR && errno != EAGAIN)
perror("recvfrom(netlink)");
return;
}
h = (struct nlmsghdr *) buf;
while (left >= (int) sizeof(*h)) {
int len, plen;
len = h->nlmsg_len;
plen = len - sizeof(*h);
if (len > left || plen < 0) {
printf("Malformed netlink message: "
"len=%d left=%d plen=%d", len, left, plen);
break;
}
switch (h->nlmsg_type) {
case RTM_NEWLINK:
vlan_read_ifnames(h, plen, 0, hapd);
break;
case RTM_DELLINK:
vlan_read_ifnames(h, plen, 1, hapd);
break;
}
len = NLMSG_ALIGN(len);
left -= len;
h = (struct nlmsghdr *) ((char *) h + len);
}
if (left > 0) {
printf("%d extra bytes in the end of netlink message",
left);
}
}
static struct full_dynamic_vlan *
full_dynamic_vlan_init(struct hostapd_data *hapd)
{
struct sockaddr_nl local;
struct full_dynamic_vlan *priv;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
return NULL;
vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (priv->s < 0) {
perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
os_free(priv);
return NULL;
}
os_memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = RTMGRP_LINK;
if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
perror("bind(netlink)");
close(priv->s);
os_free(priv);
return NULL;
}
if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
{
close(priv->s);
os_free(priv);
return NULL;
}
return priv;
}
static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
{
if (priv == NULL)
return;
eloop_unregister_read_sock(priv->s);
close(priv->s);
os_free(priv);
}
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid, const char *dyn_vlan)
{
int i;
if (dyn_vlan == NULL)
return 0;
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
* functions for setting up dynamic broadcast keys. */
for (i = 0; i < 4; i++) {
if (mssid->wep.key[i] &&
hostapd_set_encryption(dyn_vlan, hapd, "WEP", NULL,
i, mssid->wep.key[i],
mssid->wep.len[i],
i == mssid->wep.idx)) {
printf("VLAN: Could not set WEP encryption for "
"dynamic VLAN.\n");
return -1;
}
}
return 0;
}
static int vlan_dynamic_add(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
while (vlan) {
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
{
if (errno != EEXIST) {
printf("Could not add VLAN iface: %s: %s\n",
vlan->ifname, strerror(errno));
return -1;
}
}
vlan = vlan->next;
}
return 0;
}
static void vlan_dynamic_remove(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
struct hostapd_vlan *next;
while (vlan) {
next = vlan->next;
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
NULL)) {
printf("Could not remove VLAN iface: %s: %s\n",
vlan->ifname, strerror(errno));
}
#ifdef CONFIG_FULL_DYNAMIC_VLAN
if (vlan->clean)
vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
vlan = next;
}
}
int vlan_init(struct hostapd_data *hapd)
{
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
return -1;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
return 0;
}
void vlan_deinit(struct hostapd_data *hapd)
{
vlan_dynamic_remove(hapd, hapd->conf->vlan);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss)
{
vlan_dynamic_remove(hapd, oldbss->vlan);
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
return -1;
return 0;
}
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id)
{
struct hostapd_vlan *n;
char *ifname, *pos;
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
ifname = os_strdup(vlan->ifname);
if (ifname == NULL)
return NULL;
pos = os_strchr(ifname, '#');
if (pos == NULL) {
os_free(ifname);
return NULL;
}
*pos++ = '\0';
n = os_zalloc(sizeof(*n));
if (n == NULL) {
os_free(ifname);
return NULL;
}
n->vlan_id = vlan_id;
n->dynamic_vlan = 1;
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
pos);
os_free(ifname);
if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
os_free(n);
return NULL;
}
n->next = hapd->conf->vlan;
hapd->conf->vlan = n;
return n;
}
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
struct hostapd_vlan *vlan;
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
return 1;
vlan = hapd->conf->vlan;
while (vlan) {
if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan--;
break;
}
vlan = vlan->next;
}
if (vlan == NULL)
return 1;
if (vlan->dynamic_vlan == 0)
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
return 0;
}

31
hostapd/vlan_init.h Normal file
View File

@ -0,0 +1,31 @@
/*
* hostapd / VLAN initialization
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef VLAN_INIT_H
#define VLAN_INIT_H
int vlan_init(struct hostapd_data *hapd);
void vlan_deinit(struct hostapd_data *hapd);
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
struct hostapd_bss_config *oldbss);
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id);
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid,
const char *dyn_vlan);
#endif /* VLAN_INIT_H */

40
hostapd/wired.conf Normal file
View File

@ -0,0 +1,40 @@
##### hostapd configuration file ##############################################
# Empty lines and lines starting with # are ignored
# Example configuration file for wired authenticator. See hostapd.conf for
# more details.
interface=eth0
driver=wired
logger_stdout=-1
logger_stdout_level=1
debug=2
dump_file=/tmp/hostapd.dump
ieee8021x=1
eap_reauth_period=3600
use_pae_group_addr=1
##### RADIUS configuration ####################################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
# authentication with external ACL for MAC addresses, and accounting
# The own IP address of the access point (used as NAS-IP-Address)
own_ip_addr=127.0.0.1
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
# a unique to the NAS within the scope of the RADIUS server. For example, a
# fully qualified domain name can be used here.
nas_identifier=ap.example.com
# RADIUS authentication server
auth_server_addr=127.0.0.1
auth_server_port=1812
auth_server_shared_secret=radius
# RADIUS accounting server
acct_server_addr=127.0.0.1
acct_server_port=1813
acct_server_shared_secret=radius

262
hostapd/wme.c Normal file
View File

@ -0,0 +1,262 @@
/*
* hostapd / WMM (Wi-Fi Multimedia)
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "wme.h"
#include "sta_info.h"
#include "driver.h"
/* TODO: maintain separate sequence and fragment numbers for each AC
* TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
* if only WME stations are receiving a certain group */
static u8 wme_oui[3] = { 0x00, 0x50, 0xf2 };
/* Add WME Parameter Element to Beacon and Probe Response frames. */
u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
struct wme_parameter_element *wme =
(struct wme_parameter_element *) (pos + 2);
int e;
if (!hapd->conf->wme_enabled)
return eid;
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
wme->oui[0] = 0x00;
wme->oui[1] = 0x50;
wme->oui[2] = 0xf2;
wme->oui_type = WME_OUI_TYPE;
wme->oui_subtype = WME_OUI_SUBTYPE_PARAMETER_ELEMENT;
wme->version = WME_VERSION;
wme->acInfo = hapd->parameter_set_count & 0xf;
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wme_ac_parameter *ac = &wme->ac[e];
struct hostapd_wme_ac_params *acp =
&hapd->iconf->wme_ac_params[e];
ac->aifsn = acp->aifs;
ac->acm = acp->admission_control_mandatory;
ac->aci = e;
ac->reserved = 0;
ac->eCWmin = acp->cwmin;
ac->eCWmax = acp->cwmax;
ac->txopLimit = host_to_le16(acp->txopLimit);
}
pos = (u8 *) (wme + 1);
eid[1] = pos - eid - 2; /* element length */
return pos;
}
/* This function is called when a station sends an association request with
* WME info element. The function returns zero on success or non-zero on any
* error in WME element. eid does not include Element ID and Length octets. */
int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
{
struct wme_information_element *wme;
wpa_hexdump(MSG_MSGDUMP, "WME IE", eid, len);
if (len < sizeof(struct wme_information_element)) {
wpa_printf(MSG_DEBUG, "Too short WME IE (len=%lu)",
(unsigned long) len);
return -1;
}
wme = (struct wme_information_element *) eid;
wpa_printf(MSG_DEBUG, "Validating WME IE: OUI %02x:%02x:%02x "
"OUI type %d OUI sub-type %d version %d",
wme->oui[0], wme->oui[1], wme->oui[2], wme->oui_type,
wme->oui_subtype, wme->version);
if (os_memcmp(wme->oui, wme_oui, sizeof(wme_oui)) != 0 ||
wme->oui_type != WME_OUI_TYPE ||
wme->oui_subtype != WME_OUI_SUBTYPE_INFORMATION_ELEMENT ||
wme->version != WME_VERSION) {
wpa_printf(MSG_DEBUG, "Unsupported WME IE OUI/Type/Subtype/"
"Version");
return -1;
}
return 0;
}
/* This function is called when a station sends an ACK frame for an AssocResp
* frame (status=success) and the matching AssocReq contained a WME element.
*/
int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
{
/* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
if (sta->flags & WLAN_STA_WME)
hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
WLAN_STA_WME, ~0);
else
hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
0, ~WLAN_STA_WME);
return 0;
}
static void wme_send_action(struct hostapd_data *hapd, const u8 *addr,
const struct wme_tspec_info_element *tspec,
u8 action_code, u8 dialogue_token, u8 status_code)
{
u8 buf[256];
struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
struct wme_tspec_info_element *t =
(struct wme_tspec_info_element *)
m->u.action.u.wme_action.variable;
int len;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"action response - reason %d", status_code);
os_memset(buf, 0, sizeof(buf));
m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(m->da, addr, ETH_ALEN);
os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
m->u.action.category = WLAN_ACTION_WMM;
m->u.action.u.wme_action.action_code = action_code;
m->u.action.u.wme_action.dialog_token = dialogue_token;
m->u.action.u.wme_action.status_code = status_code;
os_memcpy(t, tspec, sizeof(struct wme_tspec_info_element));
len = ((u8 *) (t + 1)) - buf;
if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0)
perror("wme_send_action: send");
}
/* given frame data payload size in bytes, and data_rate in bits per second
* returns time to complete frame exchange */
/* FIX: should not use floating point types */
static double wme_frame_exchange_time(int bytes, int data_rate, int encryption,
int cts_protection)
{
/* TODO: account for MAC/PHY headers correctly */
/* TODO: account for encryption headers */
/* TODO: account for WDS headers */
/* TODO: account for CTS protection */
/* TODO: account for SIFS + ACK at minimum PHY rate */
return (bytes + 400) * 8.0 / data_rate;
}
static void wme_setup_request(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt,
struct wme_tspec_info_element *tspec, size_t len)
{
/* FIX: should not use floating point types */
double medium_time, pps;
/* TODO: account for airtime and answer no to tspec setup requests
* when none left!! */
pps = (tspec->mean_data_rate / 8.0) / tspec->nominal_msdu_size;
medium_time = (tspec->surplus_bandwidth_allowance / 8) * pps *
wme_frame_exchange_time(tspec->nominal_msdu_size,
tspec->minimum_phy_rate, 0, 0);
tspec->medium_time = medium_time * 1000000.0 / 32.0;
wme_send_action(hapd, mgmt->sa, tspec, WME_ACTION_CODE_SETUP_RESPONSE,
mgmt->u.action.u.wme_action.dialog_token,
WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED);
}
void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len)
{
int action_code;
int left = len - IEEE80211_HDRLEN - 4;
u8 *pos = ((u8 *) mgmt) + IEEE80211_HDRLEN + 4;
struct ieee802_11_elems elems;
struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
/* check that the request comes from a valid station */
if (!sta ||
(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WME)) !=
(WLAN_STA_ASSOC | WLAN_STA_WME)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"wme action received is not from associated wme"
" station");
/* TODO: respond with action frame refused status code */
return;
}
/* extract the tspec info element */
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wme_action - could not parse wme "
"action");
/* TODO: respond with action frame invalid parameters status
* code */
return;
}
if (!elems.wme_tspec ||
elems.wme_tspec_len != (sizeof(struct wme_tspec_info_element) - 2))
{
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wme_action - missing or wrong length "
"tspec");
/* TODO: respond with action frame invalid parameters status
* code */
return;
}
/* TODO: check the request is for an AC with ACM set, if not, refuse
* request */
action_code = mgmt->u.action.u.wme_action.action_code;
switch (action_code) {
case WME_ACTION_CODE_SETUP_REQUEST:
wme_setup_request(hapd, mgmt, (struct wme_tspec_info_element *)
elems.wme_tspec, len);
return;
#if 0
/* TODO: needed for client implementation */
case WME_ACTION_CODE_SETUP_RESPONSE:
wme_setup_request(hapd, mgmt, len);
return;
/* TODO: handle station teardown requests */
case WME_ACTION_CODE_TEARDOWN:
wme_teardown(hapd, mgmt, len);
return;
#endif
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wme_action - unknown action code %d",
action_code);
}

129
hostapd/wme.h Normal file
View File

@ -0,0 +1,129 @@
/*
* hostapd / WMM (Wi-Fi Multimedia)
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WME_H
#define WME_H
#ifdef __linux__
#include <endian.h>
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
#include <sys/types.h>
#include <sys/endian.h>
#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
* defined(__DragonFly__) */
extern inline u16 tsinfo(int tag1d, int contention_based, int direction)
{
return (tag1d << 11) | (contention_based << 7) | (direction << 5) |
(tag1d << 1);
}
struct wme_information_element {
/* required fields for WME version 1 */
u8 oui[3];
u8 oui_type;
u8 oui_subtype;
u8 version;
u8 acInfo;
} __attribute__ ((packed));
struct wme_ac_parameter {
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* byte 1 */
u8 aifsn:4,
acm:1,
aci:2,
reserved:1;
/* byte 2 */
u8 eCWmin:4,
eCWmax:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
/* byte 1 */
u8 reserved:1,
aci:2,
acm:1,
aifsn:4;
/* byte 2 */
u8 eCWmax:4,
eCWmin:4;
#else
#error "Please fix <endian.h>"
#endif
/* bytes 3 & 4 */
le16 txopLimit;
} __attribute__ ((packed));
struct wme_parameter_element {
/* required fields for WME version 1 */
u8 oui[3];
u8 oui_type;
u8 oui_subtype;
u8 version;
u8 acInfo;
u8 reserved;
struct wme_ac_parameter ac[4];
} __attribute__ ((packed));
struct wme_tspec_info_element {
u8 eid;
u8 length;
u8 oui[3];
u8 oui_type;
u8 oui_subtype;
u8 version;
u16 ts_info;
u16 nominal_msdu_size;
u16 maximum_msdu_size;
u32 minimum_service_interval;
u32 maximum_service_interval;
u32 inactivity_interval;
u32 start_time;
u32 minimum_data_rate;
u32 mean_data_rate;
u32 maximum_burst_size;
u32 minimum_phy_rate;
u32 peak_data_rate;
u32 delay_bound;
u16 surplus_bandwidth_allowance;
u16 medium_time;
} __attribute__ ((packed));
/* Access Categories */
enum {
WME_AC_BK = 1,
WME_AC_BE = 0,
WME_AC_VI = 2,
WME_AC_VO = 3
};
struct ieee80211_mgmt;
u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid);
int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len);
int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len);
#endif /* WME_H */

2447
hostapd/wpa.c Normal file

File diff suppressed because it is too large Load Diff

284
hostapd/wpa.h Normal file
View File

@ -0,0 +1,284 @@
/*
* 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.
*/
#ifndef WPA_AUTH_H
#define WPA_AUTH_H
#include "eapol_common.h"
#include "wpa_common.h"
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
*/
struct ft_rrb_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
le16 action_length; /* little endian length of action_frame */
u8 ap_address[ETH_ALEN];
/*
* Followed by action_length bytes of FT Action frame (from Category
* field to the end of Action Frame body.
*/
} STRUCT_PACKED;
#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
#define FT_PACKET_REQUEST 0
#define FT_PACKET_RESPONSE 1
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
#define FT_PACKET_R0KH_R1KH_PULL 200
#define FT_PACKET_R0KH_R1KH_RESP 201
#define FT_PACKET_R0KH_R1KH_PUSH 202
#ifndef ETH_P_RRB
#define ETH_P_RRB 0x890D
#endif /* ETH_P_RRB */
#define FT_R0KH_R1KH_PULL_DATA_LEN 44
#define FT_R0KH_R1KH_RESP_DATA_LEN 76
#define FT_R0KH_R1KH_PUSH_DATA_LEN 80
struct ft_r0kh_r1kh_pull_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
le16 data_length; /* little endian length of data (44) */
u8 ap_address[ETH_ALEN];
u8 nonce[16];
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 r1kh_id[FT_R1KH_ID_LEN];
u8 s1kh_id[ETH_ALEN];
u8 pad[4]; /* 8-octet boundary for AES key wrap */
u8 key_wrap_extra[8];
} STRUCT_PACKED;
struct ft_r0kh_r1kh_resp_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
le16 data_length; /* little endian length of data (76) */
u8 ap_address[ETH_ALEN];
u8 nonce[16]; /* copied from pull */
u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
u8 pmk_r1[PMK_LEN];
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 pad[4]; /* 8-octet boundary for AES key wrap */
u8 key_wrap_extra[8];
} STRUCT_PACKED;
struct ft_r0kh_r1kh_push_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
le16 data_length; /* little endian length of data (80) */
u8 ap_address[ETH_ALEN];
/* Encrypted with AES key-wrap */
u8 timestamp[4]; /* current time in seconds since unix epoch, little
* endian */
u8 r1kh_id[FT_R1KH_ID_LEN];
u8 s1kh_id[ETH_ALEN];
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 key_wrap_extra[8];
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
/* per STA state machine data */
struct wpa_authenticator;
struct wpa_state_machine;
struct rsn_pmksa_cache_entry;
struct eapol_state_machine;
struct ft_remote_r0kh {
struct ft_remote_r0kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R0KH_ID_MAX_LEN];
size_t id_len;
u8 key[16];
};
struct ft_remote_r1kh {
struct ft_remote_r1kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R1KH_ID_LEN];
u8 key[16];
};
struct wpa_auth_config {
int wpa;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
int peerkey;
int wme_enabled;
int okc;
#ifdef CONFIG_IEEE80211W
enum {
WPA_NO_IEEE80211W = 0,
WPA_IEEE80211W_OPTIONAL = 1,
WPA_IEEE80211W_REQUIRED = 2
} ieee80211w;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
#define SSID_LEN 32
u8 ssid[SSID_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
size_t r0_key_holder_len;
u8 r1_key_holder[FT_R1KH_ID_LEN];
u32 r0_key_lifetime;
u32 reassociation_deadline;
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
#endif /* CONFIG_IEEE80211R */
};
typedef enum {
LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
} logger_level;
typedef enum {
WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
} wpa_eapol_variable;
struct wpa_auth_callbacks {
void *ctx;
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
void (*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);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, const char *alg, const u8 *addr,
int idx, u8 *key, size_t key_len);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*get_seqnum_igtk)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
void *ctx), void *cb_ctx);
int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
void *ctx), void *cb_ctx);
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
size_t data_len);
#ifdef CONFIG_IEEE80211R
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);
#endif /* CONFIG_IEEE80211R */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
struct wpa_auth_callbacks *cb);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
enum {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
WPA_INVALID_MDIE, WPA_INVALID_PROTO
};
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm);
void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len);
typedef enum {
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
WPA_REAUTH_EAPOL, WPA_ASSOC_FT
} wpa_event;
void wpa_remove_ptk(struct wpa_state_machine *sm);
void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
void wpa_auth_sm_notify(struct wpa_state_machine *sm);
void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry *
wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
size_t *len);
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
int session_timeout, struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
#ifdef CONFIG_IEEE80211R
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *data, size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
#endif /* WPA_AUTH_H */

221
hostapd/wpa_auth_i.h Normal file
View File

@ -0,0 +1,221 @@
/*
* 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.
*/
#ifndef WPA_AUTH_I_H
#define WPA_AUTH_I_H
/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
#define RSNA_MAX_EAPOL_RETRIES 4
struct wpa_group;
struct wpa_stsl_negotiation {
struct wpa_stsl_negotiation *next;
u8 initiator[ETH_ALEN];
u8 peer[ETH_ALEN];
};
struct wpa_state_machine {
struct wpa_authenticator *wpa_auth;
struct wpa_group *group;
u8 addr[ETH_ALEN];
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
} wpa_ptk_state;
enum {
WPA_PTK_GROUP_IDLE = 0,
WPA_PTK_GROUP_REKEYNEGOTIATING,
WPA_PTK_GROUP_REKEYESTABLISHED,
WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state;
Boolean Init;
Boolean DeauthenticationRequest;
Boolean AuthenticationRequest;
Boolean ReAuthenticationRequest;
Boolean Disconnect;
int TimeoutCtr;
int GTimeoutCtr;
Boolean TimeoutEvt;
Boolean EAPOLKeyReceived;
Boolean EAPOLKeyPairwise;
Boolean EAPOLKeyRequest;
Boolean MICVerified;
Boolean GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 PMK[PMK_LEN];
struct wpa_ptk PTK;
Boolean PTK_valid;
Boolean pairwise_set;
int keycount;
Boolean Pair;
struct {
u8 counter[WPA_REPLAY_COUNTER_LEN];
Boolean valid;
} 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;
Boolean PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len;
unsigned int changed:1;
unsigned int in_step_loop:1;
unsigned int pending_deinit:1;
unsigned int started:1;
unsigned int mgmt_frame_prot:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
u8 *wpa_ie;
size_t wpa_ie_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
} wpa;
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
struct rsn_pmksa_cache_entry *pmksa;
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
#ifdef CONFIG_IEEE80211R
u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
size_t xxkey_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
size_t r0kh_id_len;
#endif /* CONFIG_IEEE80211R */
};
/* per group key state machine data */
struct wpa_group {
struct wpa_group *next;
int vlan_id;
Boolean GInit;
int GKeyDoneStations;
Boolean GTKReKey;
int GTK_len;
int GN, GM;
Boolean GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN];
enum {
WPA_GROUP_GTK_INIT = 0,
WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
} wpa_group_state;
u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
Boolean changed;
#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
};
struct wpa_ft_pmk_cache;
/* per authenticator data */
struct wpa_authenticator {
struct wpa_group *group;
unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
u32 dot11RSNAAuthenticationSuiteSelected;
u32 dot11RSNAPairwiseCipherSelected;
u32 dot11RSNAGroupCipherSelected;
u8 dot11RSNAPMKIDUsed[PMKID_LEN];
u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
u32 dot11RSNAGroupCipherRequested; /* FIX: update */
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
unsigned int dot11RSNA4WayHandshakeFailures;
struct wpa_stsl_negotiation *stsl_negotiations;
struct wpa_auth_config conf;
struct wpa_auth_callbacks cb;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 addr[ETH_ALEN];
struct rsn_pmksa_cache *pmksa;
struct wpa_ft_pmk_cache *ft_pmk_cache;
};
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *fmt, ...);
void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int key_info,
const u8 *key_rsc, const u8 *nonce,
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version);
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx);
int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx);
#ifdef CONFIG_PEERKEY
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
#endif /* CONFIG_IEEE80211R */
#endif /* WPA_AUTH_I_H */

864
hostapd/wpa_auth_ie.c Normal file
View File

@ -0,0 +1,864 @@
/*
* 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.
*/
#include "includes.h"
#include "common.h"
#include "config.h"
#include "ieee802_11.h"
#include "eapol_sm.h"
#include "wpa.h"
#include "pmksa_cache.h"
#include "wpa_auth_ie.h"
#include "wpa_auth_i.h"
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;
hdr = (struct wpa_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
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 {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
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++;
}
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->wpa_pairwise);
return -1;
}
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
count = pos;
pos += 2;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
conf->wpa_key_mgmt);
return -1;
}
WPA_PUT_LE16(count, num_suites);
/* WPA Capabilities; use defaults, so no need to include it */
hdr->len = (pos - buf) - 2;
return pos - buf;
}
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;
u8 *pos, *count;
u16 capab;
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 {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
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);
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);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->rsn_pairwise);
return -1;
}
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
count = pos;
pos += 2;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211W */
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
conf->wpa_key_mgmt);
return -1;
}
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
capab = 0;
if (conf->rsn_preauth)
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->peerkey)
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
if (conf->wme_enabled) {
/* 4 PTKSA replay counters when using WME */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != WPA_NO_IEEE80211W) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == IEEE80211W_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
WPA_PUT_LE16(pos, capab);
pos += 2;
if (pmkid) {
if (pos + 2 + PMKID_LEN > buf + len)
return -1;
/* PMKID Count */
WPA_PUT_LE16(pos, 1);
pos += 2;
os_memcpy(pos, pmkid, PMKID_LEN);
pos += PMKID_LEN;
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != WPA_NO_IEEE80211W) {
if (pos + 2 + 4 > buf + len)
return -1;
if (pmkid == NULL) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
hdr->len = (pos - buf) - 2;
return pos - buf;
}
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
int res;
pos = buf;
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_IEEE80211R
if (wpa_auth->conf.wpa_key_mgmt &
(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#endif /* CONFIG_IEEE80211R */
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
res = wpa_write_wpa_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie = os_malloc(pos - buf);
if (wpa_auth->wpa_ie == NULL)
return -1;
os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
wpa_auth->wpa_ie_len = pos - buf;
return 0;
}
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len)
{
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
RSN_SELECTOR_PUT(pos, kde);
pos += RSN_SELECTOR_LEN;
os_memcpy(pos, data, data_len);
pos += data_len;
if (data2) {
os_memcpy(pos, data2, data2_len);
pos += data2_len;
}
return pos;
}
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;
const u8 *spa;
const u8 *pmkid;
};
static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
{
struct wpa_auth_okc_iter_data *data = ctx;
data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
data->pmkid);
if (data->pmksa)
return 1;
return 0;
}
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len)
{
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
size_t i;
const u8 *pmkid = NULL;
if (wpa_auth == NULL || sm == NULL)
return WPA_NOT_ENABLED;
if (wpa_ie == NULL || wpa_ie_len < 1)
return WPA_INVALID_IE;
if (wpa_ie[0] == WLAN_EID_RSN)
version = WPA_PROTO_RSN;
else
version = WPA_PROTO_WPA;
if (!(wpa_auth->conf.wpa & version)) {
wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
version, MAC2STR(sm->addr));
return WPA_INVALID_PROTO;
}
if (version == WPA_PROTO_RSN) {
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
#ifdef CONFIG_IEEE80211R
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
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 = 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 = 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);
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
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;
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_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) {
wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
MACSTR " (res=%d)", MAC2STR(sm->addr), res);
wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
return WPA_INVALID_IE;
}
if (data.group_cipher != wpa_auth->conf.wpa_group) {
wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
MACSTR, data.group_cipher, MAC2STR(sm->addr));
return WPA_INVALID_GROUP;
}
key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
return WPA_INVALID_AKMP;
}
if (0) {
}
#ifdef CONFIG_IEEE80211R
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
if (version == WPA_PROTO_RSN)
ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
if (!ciphers) {
wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
"from " MACSTR,
version == WPA_PROTO_RSN ? "RSN" : "WPA",
data.pairwise_cipher, MAC2STR(sm->addr));
return WPA_INVALID_PAIRWISE;
}
#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == WPA_IEEE80211W_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
"required, but client did not enable it");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
if (ciphers & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "Management frame protection "
"cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "Unsupported management group "
"cipher %d", data.mgmt_group_cipher);
return WPA_INVALID_MGMT_GROUP_CIPHER;
}
}
if (wpa_auth->conf.ieee80211w == WPA_NO_IEEE80211W ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
else
sm->mgmt_frame_prot = 1;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
"MDIE not included");
return WPA_INVALID_MDIE;
}
if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
return WPA_INVALID_MDIE;
}
}
#endif /* CONFIG_IEEE80211R */
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
sm->wpa = WPA_VERSION_WPA2;
else
sm->wpa = WPA_VERSION_WPA;
sm->pmksa = NULL;
for (i = 0; i < data.num_pmkid; i++) {
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
&data.pmkid[i * PMKID_LEN], PMKID_LEN);
sm->pmksa = pmksa_cache_get(wpa_auth->pmksa, sm->addr,
&data.pmkid[i * PMKID_LEN]);
if (sm->pmksa) {
pmkid = sm->pmksa->pmkid;
break;
}
}
for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
i < data.num_pmkid; i++) {
struct wpa_auth_okc_iter_data idata;
idata.pmksa = NULL;
idata.aa = wpa_auth->addr;
idata.spa = sm->addr;
idata.pmkid = &data.pmkid[i * PMKID_LEN];
wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
if (idata.pmksa) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"OKC match for PMKID");
sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
idata.pmksa,
wpa_auth->addr,
idata.pmkid);
pmkid = idata.pmkid;
break;
}
}
if (sm->pmksa) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",
sm->pmksa->eap_type_authsrv,
sm->pmksa->vlan_id);
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
}
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
if (sm->wpa_ie == NULL)
return WPA_ALLOC_FAIL;
}
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
return WPA_IE_OK;
}
/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
* @end: Pointer to the end of the Key Data buffer
* @ie: Pointer to parsed IE data
* Returns: 0 on success, 1 if end mark is found, -1 on failure
*/
static int wpa_parse_generic(const u8 *pos, const u8 *end,
struct wpa_eapol_ie_parse *ie)
{
if (pos[1] == 0)
return 1;
if (pos[1] >= 6 &&
RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
pos[2 + WPA_SELECTOR_LEN] == 1 &&
pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
ie->wpa_ie = pos;
ie->wpa_ie_len = pos[1] + 2;
return 0;
}
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#ifdef CONFIG_PEERKEY
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
ie->smk = pos + 2 + RSN_SELECTOR_LEN;
ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
ie->error = pos + 2 + RSN_SELECTOR_LEN;
ie->error_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#endif /* CONFIG_IEEE80211W */
return 0;
}
/**
* wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
* @buf: Pointer to the Key Data buffer
* @len: Key Data Length
* @ie: Pointer to parsed IE data
* Returns: 0 on success, -1 on failure
*/
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
{
const u8 *pos, *end;
int ret = 0;
os_memset(ie, 0, sizeof(*ie));
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
if (pos + 2 + pos[1] > end) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
"underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
buf, len);
ret = -1;
break;
}
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
ie->rsn_ie_len = pos[1] + 2;
#ifdef CONFIG_IEEE80211R
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
ie->mdie_len = pos[1] + 2;
#endif /* CONFIG_IEEE80211R */
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
break;
if (ret > 0) {
ret = 0;
break;
}
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
"Key Data IE", pos, 2 + pos[1]);
}
}
return ret;
}
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
}

54
hostapd/wpa_auth_ie.h Normal file
View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
struct wpa_eapol_ie_parse {
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *rsn_ie;
size_t rsn_ie_len;
const u8 *pmkid;
const u8 *gtk;
size_t gtk_len;
const u8 *mac_addr;
size_t mac_addr_len;
#ifdef CONFIG_PEERKEY
const u8 *smk;
size_t smk_len;
const u8 *nonce;
size_t nonce_len;
const u8 *lifetime;
size_t lifetime_len;
const u8 *error;
size_t error_len;
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
const u8 *igtk;
size_t igtk_len;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
const u8 *mdie;
size_t mdie_len;
#endif /* CONFIG_IEEE80211R */
};
int wpa_parse_kde_ies(const u8 *buf, size_t len,
struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
#endif /* WPA_AUTH_IE_H */

1499
hostapd/wpa_ft.c Normal file

File diff suppressed because it is too large Load Diff

998
hostapd/wps_hostapd.c Normal file
View File

@ -0,0 +1,998 @@
/*
* hostapd / WPS integration
* Copyright (c) 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.
*/
#include "includes.h"
#include "hostapd.h"
#include "driver.h"
#include "eloop.h"
#include "uuid.h"
#include "wpa_ctrl.h"
#include "ieee802_11_defs.h"
#include "sta_info.h"
#include "eapol_sm.h"
#include "wps/wps.h"
#include "wps/wps_defs.h"
#include "wps/wps_dev_attr.h"
#include "wps_hostapd.h"
#ifdef CONFIG_WPS_UPNP
#include "wps/wps_upnp.h"
static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
struct wps_context *wps);
static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
#endif /* CONFIG_WPS_UPNP */
static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
size_t psk_len)
{
struct hostapd_data *hapd = ctx;
struct hostapd_wpa_psk *p;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
MACSTR, MAC2STR(mac_addr));
wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
if (psk_len != PMK_LEN) {
wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
(unsigned long) psk_len);
return -1;
}
/* Add the new PSK to runtime PSK list */
p = os_zalloc(sizeof(*p));
if (p == NULL)
return -1;
os_memcpy(p->addr, mac_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
p->next = ssid->wpa_psk;
ssid->wpa_psk = p;
if (ssid->wpa_psk_file) {
FILE *f;
char hex[PMK_LEN * 2 + 1];
/* Add the new PSK to PSK list file */
f = fopen(ssid->wpa_psk_file, "a");
if (f == NULL) {
wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
"'%s'", ssid->wpa_psk_file);
return -1;
}
wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
fclose(f);
}
return 0;
}
static int hostapd_wps_set_ie_cb(void *ctx, const u8 *beacon_ie,
size_t beacon_ie_len, const u8 *probe_resp_ie,
size_t probe_resp_ie_len)
{
struct hostapd_data *hapd = ctx;
os_free(hapd->wps_beacon_ie);
if (beacon_ie_len == 0) {
hapd->wps_beacon_ie = NULL;
hapd->wps_beacon_ie_len = 0;
} else {
hapd->wps_beacon_ie = os_malloc(beacon_ie_len);
if (hapd->wps_beacon_ie == NULL) {
hapd->wps_beacon_ie_len = 0;
return -1;
}
os_memcpy(hapd->wps_beacon_ie, beacon_ie, beacon_ie_len);
hapd->wps_beacon_ie_len = beacon_ie_len;
}
hostapd_set_wps_beacon_ie(hapd, hapd->wps_beacon_ie,
hapd->wps_beacon_ie_len);
os_free(hapd->wps_probe_resp_ie);
if (probe_resp_ie_len == 0) {
hapd->wps_probe_resp_ie = NULL;
hapd->wps_probe_resp_ie_len = 0;
} else {
hapd->wps_probe_resp_ie = os_malloc(probe_resp_ie_len);
if (hapd->wps_probe_resp_ie == NULL) {
hapd->wps_probe_resp_ie_len = 0;
return -1;
}
os_memcpy(hapd->wps_probe_resp_ie, probe_resp_ie,
probe_resp_ie_len);
hapd->wps_probe_resp_ie_len = probe_resp_ie_len;
}
hostapd_set_wps_probe_resp_ie(hapd, hapd->wps_probe_resp_ie,
hapd->wps_probe_resp_ie_len);
return 0;
}
static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
const struct wps_device_data *dev)
{
struct hostapd_data *hapd = ctx;
char uuid[40], txt[400];
int len;
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
return;
wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
"%s " MACSTR " [%s|%s|%s|%s|%s|%d-%08X-%d]",
uuid, MAC2STR(dev->mac_addr), dev->device_name,
dev->manufacturer, dev->model_name,
dev->model_number, dev->serial_number,
dev->categ, dev->oui, dev->sub_categ);
if (len > 0 && len < (int) sizeof(txt))
wpa_msg(hapd, MSG_INFO, "%s", txt);
if (hapd->conf->wps_pin_requests) {
FILE *f;
struct os_time t;
f = fopen(hapd->conf->wps_pin_requests, "a");
if (f == NULL)
return;
os_get_time(&t);
fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
"\t%d-%08X-%d\n",
t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
dev->manufacturer, dev->model_name, dev->model_number,
dev->serial_number,
dev->categ, dev->oui, dev->sub_categ);
fclose(f);
}
}
static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
const u8 *uuid_e)
{
struct hostapd_data *hapd = ctx;
char uuid[40];
if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
return;
wpa_msg(hapd, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
MAC2STR(mac_addr), uuid);
}
static int str_starts(const char *str, const char *start)
{
return os_strncmp(str, start, os_strlen(start)) == 0;
}
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
if (hostapd_reload_config(iface) < 0) {
wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
"configuration");
}
}
static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
{
struct hostapd_data *hapd = ctx;
FILE *oconf, *nconf;
size_t len, i;
char *tmp_fname;
char buf[1024];
int multi_bss;
int wpa;
wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
cred->cred_attr, cred->cred_attr_len);
wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
cred->auth_type);
wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
cred->key, cred->key_len);
wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
MAC2STR(cred->mac_addr));
if ((hapd->conf->wps_cred_processing == 1 ||
hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
size_t blen = cred->cred_attr_len * 2 + 1;
char *buf = os_malloc(blen);
if (buf) {
wpa_snprintf_hex(buf, blen,
cred->cred_attr, cred->cred_attr_len);
wpa_msg(hapd, MSG_INFO, "%s%s",
WPS_EVENT_NEW_AP_SETTINGS, buf);
os_free(buf);
}
} else
wpa_msg(hapd, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
if (hapd->conf->wps_cred_processing == 1)
return 0;
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
return -1;
os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
oconf = fopen(hapd->iface->config_fname, "r");
if (oconf == NULL) {
wpa_printf(MSG_WARNING, "WPS: Could not open current "
"configuration file");
os_free(tmp_fname);
return -1;
}
nconf = fopen(tmp_fname, "w");
if (nconf == NULL) {
wpa_printf(MSG_WARNING, "WPS: Could not write updated "
"configuration file");
os_free(tmp_fname);
fclose(oconf);
return -1;
}
fprintf(nconf, "# WPS configuration - START\n");
fprintf(nconf, "wps_state=2\n");
fprintf(nconf, "ssid=");
for (i = 0; i < cred->ssid_len; i++)
fputc(cred->ssid[i], nconf);
fprintf(nconf, "\n");
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
wpa = 3;
else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
wpa = 2;
else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
wpa = 1;
else
wpa = 0;
if (wpa) {
char *prefix;
fprintf(nconf, "wpa=%d\n", wpa);
fprintf(nconf, "wpa_key_mgmt=");
prefix = "";
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
fprintf(nconf, "WPA-EAP");
prefix = " ";
}
if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
fprintf(nconf, "%sWPA-PSK", prefix);
fprintf(nconf, "\n");
fprintf(nconf, "wpa_pairwise=");
prefix = "";
if (cred->encr_type & WPS_ENCR_AES) {
fprintf(nconf, "CCMP");
prefix = " ";
}
if (cred->encr_type & WPS_ENCR_TKIP) {
fprintf(nconf, "%sTKIP", prefix);
}
fprintf(nconf, "\n");
if (cred->key_len >= 8 && cred->key_len < 64) {
fprintf(nconf, "wpa_passphrase=");
for (i = 0; i < cred->key_len; i++)
fputc(cred->key[i], nconf);
fprintf(nconf, "\n");
} else if (cred->key_len == 64) {
fprintf(nconf, "wpa_psk=");
for (i = 0; i < cred->key_len; i++)
fputc(cred->key[i], nconf);
fprintf(nconf, "\n");
} else {
wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
"for WPA/WPA2",
(unsigned long) cred->key_len);
}
fprintf(nconf, "auth_algs=1\n");
} else {
if ((cred->auth_type & WPS_AUTH_OPEN) &&
(cred->auth_type & WPS_AUTH_SHARED))
fprintf(nconf, "auth_algs=3\n");
else if (cred->auth_type & WPS_AUTH_SHARED)
fprintf(nconf, "auth_algs=2\n");
else
fprintf(nconf, "auth_algs=1\n");
if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx < 4) {
fprintf(nconf, "wep_default_key=%d\n", cred->key_idx);
fprintf(nconf, "wep_key%d=", cred->key_idx);
if (cred->key_len != 10 && cred->key_len != 26)
fputc('"', nconf);
for (i = 0; i < cred->key_len; i++)
fputc(cred->key[i], nconf);
if (cred->key_len != 10 && cred->key_len != 26)
fputc('"', nconf);
fprintf(nconf, "\n");
}
}
fprintf(nconf, "# WPS configuration - END\n");
multi_bss = 0;
while (fgets(buf, sizeof(buf), oconf)) {
if (os_strncmp(buf, "bss=", 4) == 0)
multi_bss = 1;
if (!multi_bss &&
(str_starts(buf, "ssid=") ||
str_starts(buf, "auth_algs=") ||
str_starts(buf, "wps_state=") ||
str_starts(buf, "wpa=") ||
str_starts(buf, "wpa_psk=") ||
str_starts(buf, "wpa_pairwise=") ||
str_starts(buf, "rsn_pairwise=") ||
str_starts(buf, "wpa_key_mgmt=") ||
str_starts(buf, "wpa_passphrase="))) {
fprintf(nconf, "#WPS# %s", buf);
} else
fprintf(nconf, "%s", buf);
}
fclose(nconf);
fclose(oconf);
if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
"configuration file: %s", strerror(errno));
os_free(tmp_fname);
return -1;
}
os_free(tmp_fname);
/* Schedule configuration reload after short period of time to allow
* EAP-WSC to be finished.
*/
eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
NULL);
/* TODO: dualband AP may need to update multiple configuration files */
wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
return 0;
}
static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
struct wps_event_pwd_auth_fail *data)
{
FILE *f;
if (!data->enrollee)
return;
/*
* Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
* if this happens multiple times.
*/
hapd->ap_pin_failures++;
if (hapd->ap_pin_failures < 4)
return;
wpa_msg(hapd, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
hapd->wps->ap_setup_locked = 1;
wps_registrar_update_ie(hapd->wps->registrar);
if (hapd->conf->wps_cred_processing == 1)
return;
f = fopen(hapd->iface->config_fname, "a");
if (f == NULL) {
wpa_printf(MSG_WARNING, "WPS: Could not append to the current "
"configuration file");
return;
}
fprintf(f, "# WPS AP Setup Locked based on possible attack\n");
fprintf(f, "ap_setup_locked=1\n");
fclose(f);
/* TODO: dualband AP may need to update multiple configuration files */
wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
}
static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
union wps_event_data *data)
{
struct hostapd_data *hapd = ctx;
if (event == WPS_EV_PWD_AUTH_FAIL)
hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
}
static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
{
os_free(hapd->wps_beacon_ie);
hapd->wps_beacon_ie = NULL;
hapd->wps_beacon_ie_len = 0;
hostapd_set_wps_beacon_ie(hapd, NULL, 0);
os_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
hapd->wps_probe_resp_ie_len = 0;
hostapd_set_wps_probe_resp_ie(hapd, NULL, 0);
}
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf)
{
struct wps_context *wps;
struct wps_registrar_config cfg;
if (conf->wps_state == 0) {
hostapd_wps_clear_ies(hapd);
return 0;
}
wps = os_zalloc(sizeof(*wps));
if (wps == NULL)
return -1;
wps->cred_cb = hostapd_wps_cred_cb;
wps->event_cb = hostapd_wps_event_cb;
wps->cb_ctx = hapd;
os_memset(&cfg, 0, sizeof(cfg));
wps->wps_state = hapd->conf->wps_state;
wps->ap_setup_locked = hapd->conf->ap_setup_locked;
if (is_nil_uuid(hapd->conf->uuid)) {
uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
wps->uuid, UUID_LEN);
} else
os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
wps->ssid_len = hapd->conf->ssid.ssid_len;
os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
wps->ap = 1;
os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
wps->dev.device_name = hapd->conf->device_name ?
os_strdup(hapd->conf->device_name) : NULL;
wps->dev.manufacturer = hapd->conf->manufacturer ?
os_strdup(hapd->conf->manufacturer) : NULL;
wps->dev.model_name = hapd->conf->model_name ?
os_strdup(hapd->conf->model_name) : NULL;
wps->dev.model_number = hapd->conf->model_number ?
os_strdup(hapd->conf->model_number) : NULL;
wps->dev.serial_number = hapd->conf->serial_number ?
os_strdup(hapd->conf->serial_number) : NULL;
if (hapd->conf->config_methods) {
char *m = hapd->conf->config_methods;
if (os_strstr(m, "label"))
wps->config_methods |= WPS_CONFIG_LABEL;
if (os_strstr(m, "display"))
wps->config_methods |= WPS_CONFIG_DISPLAY;
if (os_strstr(m, "push_button"))
wps->config_methods |= WPS_CONFIG_PUSHBUTTON;
if (os_strstr(m, "keypad"))
wps->config_methods |= WPS_CONFIG_KEYPAD;
}
if (hapd->conf->device_type) {
char *pos;
u8 oui[4];
/* <categ>-<OUI>-<subcateg> */
wps->dev.categ = atoi(hapd->conf->device_type);
pos = os_strchr(hapd->conf->device_type, '-');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
os_free(wps);
return -1;
}
pos++;
if (hexstr2bin(pos, oui, 4)) {
wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
os_free(wps);
return -1;
}
wps->dev.oui = WPA_GET_BE32(oui);
pos = os_strchr(pos, '-');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
os_free(wps);
return -1;
}
pos++;
wps->dev.sub_categ = atoi(pos);
}
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
if (conf->wpa & WPA_PROTO_RSN) {
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPA2PSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA2;
if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
wps->encr_types |= WPS_ENCR_AES;
if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
wps->encr_types |= WPS_ENCR_TKIP;
}
if (conf->wpa & WPA_PROTO_WPA) {
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPAPSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA;
if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
wps->encr_types |= WPS_ENCR_AES;
if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
wps->encr_types |= WPS_ENCR_TKIP;
}
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
wps->encr_types |= WPS_ENCR_NONE;
wps->auth_types |= WPS_AUTH_OPEN;
} else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
wps->encr_types |= WPS_ENCR_WEP;
if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
wps->auth_types |= WPS_AUTH_OPEN;
if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
wps->auth_types |= WPS_AUTH_SHARED;
} else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
wps->auth_types |= WPS_AUTH_OPEN;
if (conf->default_wep_key_len)
wps->encr_types |= WPS_ENCR_WEP;
else
wps->encr_types |= WPS_ENCR_NONE;
}
if (conf->ssid.wpa_psk_file) {
/* Use per-device PSKs */
} else if (conf->ssid.wpa_passphrase) {
wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
} else if (conf->ssid.wpa_psk) {
wps->network_key = os_malloc(2 * PMK_LEN + 1);
if (wps->network_key == NULL) {
os_free(wps);
return -1;
}
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL) {
os_free(wps);
return -1;
}
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
}
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
}
wps->ap_settings = conf->ap_settings;
wps->ap_settings_len = conf->ap_settings_len;
cfg.new_psk_cb = hostapd_wps_new_psk_cb;
cfg.set_ie_cb = hostapd_wps_set_ie_cb;
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
wps->registrar = wps_registrar_init(wps, &cfg);
if (wps->registrar == NULL) {
printf("Failed to initialize WPS Registrar\n");
os_free(wps->network_key);
os_free(wps);
return -1;
}
#ifdef CONFIG_WPS_UPNP
wps->friendly_name = hapd->conf->friendly_name;
wps->manufacturer_url = hapd->conf->manufacturer_url;
wps->model_description = hapd->conf->model_description;
wps->model_url = hapd->conf->model_url;
wps->upc = hapd->conf->upc;
if (hostapd_wps_upnp_init(hapd, wps) < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
wps_registrar_deinit(wps->registrar);
os_free(wps->network_key);
os_free(wps);
return -1;
}
#endif /* CONFIG_WPS_UPNP */
hapd->wps = wps;
return 0;
}
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
if (hapd->wps == NULL)
return;
#ifdef CONFIG_WPS_UPNP
hostapd_wps_upnp_deinit(hapd);
#endif /* CONFIG_WPS_UPNP */
wps_registrar_deinit(hapd->wps->registrar);
os_free(hapd->wps->network_key);
wps_device_data_free(&hapd->wps->dev);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
os_free(hapd->wps);
hapd->wps = NULL;
hostapd_wps_clear_ies(hapd);
}
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
const char *pin)
{
u8 u[UUID_LEN];
int any = 0;
if (hapd->wps == NULL)
return -1;
if (os_strcmp(uuid, "any") == 0)
any = 1;
else if (uuid_str2bin(uuid, u))
return -1;
return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
(const u8 *) pin, os_strlen(pin));
}
int hostapd_wps_button_pushed(struct hostapd_data *hapd)
{
if (hapd->wps == NULL)
return -1;
return wps_registrar_button_pushed(hapd->wps->registrar);
}
void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ie_len)
{
struct wpabuf *wps_ie;
const u8 *end, *pos, *wps;
if (hapd->wps == NULL)
return;
pos = ie;
end = ie + ie_len;
wps = NULL;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
return;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == WPS_DEV_OUI_WFA) {
wps = pos;
break;
}
pos += 2 + pos[1];
}
if (wps == NULL)
return; /* No WPS IE in Probe Request */
wps_ie = wpabuf_alloc(ie_len);
if (wps_ie == NULL)
return;
/* There may be multiple WPS IEs in the message, so need to concatenate
* their WPS Data fields */
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == WPS_DEV_OUI_WFA)
wpabuf_put_data(wps_ie, pos + 6, pos[1] - 4);
pos += 2 + pos[1];
}
if (wpabuf_len(wps_ie) > 0) {
wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
#ifdef CONFIG_WPS_UPNP
/* FIX: what exactly should be included in the WLANEvent?
* WPS attributes? Full ProbeReq frame? */
upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
UPNP_WPS_WLANEVENT_TYPE_PROBE,
wps_ie);
#endif /* CONFIG_WPS_UPNP */
}
wpabuf_free(wps_ie);
}
#ifdef CONFIG_WPS_UPNP
static struct wpabuf *
hostapd_rx_req_get_device_info(void *priv, struct upnp_wps_peer *peer)
{
struct hostapd_data *hapd = priv;
struct wps_config cfg;
struct wps_data *wps;
enum wsc_op_code op_code;
struct wpabuf *m1;
/*
* Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
* registration over UPnP with the AP acting as an Enrollee. It should
* be noted that this is frequently used just to get the device data,
* i.e., there may not be any intent to actually complete the
* registration.
*/
if (peer->wps)
wps_deinit(peer->wps);
os_memset(&cfg, 0, sizeof(cfg));
cfg.wps = hapd->wps;
cfg.pin = (u8 *) hapd->conf->ap_pin;
cfg.pin_len = os_strlen(hapd->conf->ap_pin);
wps = wps_init(&cfg);
if (wps == NULL)
return NULL;
m1 = wps_get_msg(wps, &op_code);
if (m1 == NULL) {
wps_deinit(wps);
return NULL;
}
peer->wps = wps;
return m1;
}
static struct wpabuf *
hostapd_rx_req_put_message(void *priv, struct upnp_wps_peer *peer,
const struct wpabuf *msg)
{
enum wps_process_res res;
enum wsc_op_code op_code;
/* PutMessage: msg = InMessage, return OutMessage */
res = wps_process_msg(peer->wps, WSC_UPnP, msg);
if (res == WPS_FAILURE)
return NULL;
return wps_get_msg(peer->wps, &op_code);
}
static struct wpabuf *
hostapd_rx_req_get_ap_settings(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return NULL;
}
static int hostapd_rx_req_set_ap_settings(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_del_ap_settings(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static struct wpabuf *
hostapd_rx_req_get_sta_settings(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return NULL;
}
static int hostapd_rx_req_set_sta_settings(void *priv,
const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_del_sta_settings(void *priv,
const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_put_wlan_response(
void *priv, enum upnp_wps_wlanevent_type ev_type,
const u8 *mac_addr, const struct wpabuf *msg,
enum wps_msg_type msg_type)
{
struct hostapd_data *hapd = priv;
struct sta_info *sta;
struct upnp_pending_message *p;
wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
MACSTR, ev_type, MAC2STR(mac_addr));
wpa_hexdump_ascii(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
wpabuf_head(msg), wpabuf_len(msg));
if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
"PutWLANResponse WLANEventType %d", ev_type);
return -1;
}
/*
* EAP response to ongoing to WPS Registration. Send it to EAP-WSC
* server implementation for delivery to the peer.
*/
sta = ap_get_sta(hapd, mac_addr);
if (!sta) {
/*
* Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
* Pick STA that is in an ongoing WPS registration without
* checking the MAC address.
*/
wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
"on NewWLANEventMAC; try wildcard match");
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
break;
}
}
if (!sta) {
wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
return 0;
}
p = os_zalloc(sizeof(*p));
if (p == NULL)
return -1;
os_memcpy(p->addr, sta->addr, ETH_ALEN);
p->msg = wpabuf_dup(msg);
p->type = msg_type;
p->next = hapd->wps->upnp_msgs;
hapd->wps->upnp_msgs = p;
return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
}
static int hostapd_rx_req_set_selected_registrar(void *priv,
const struct wpabuf *msg)
{
struct hostapd_data *hapd = priv;
return wps_registrar_set_selected_registrar(hapd->wps->registrar, msg);
}
static int hostapd_rx_req_reboot_ap(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_reset_ap(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_reboot_sta(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_rx_req_reset_sta(void *priv, const struct wpabuf *msg)
{
wpa_printf(MSG_DEBUG, "WPS UPnP: TODO %s", __func__);
return -1;
}
static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
struct wps_context *wps)
{
struct upnp_wps_device_ctx *ctx;
if (!hapd->conf->upnp_iface)
return 0;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return -1;
ctx->rx_req_get_device_info = hostapd_rx_req_get_device_info;
ctx->rx_req_put_message = hostapd_rx_req_put_message;
ctx->rx_req_get_ap_settings = hostapd_rx_req_get_ap_settings;
ctx->rx_req_set_ap_settings = hostapd_rx_req_set_ap_settings;
ctx->rx_req_del_ap_settings = hostapd_rx_req_del_ap_settings;
ctx->rx_req_get_sta_settings = hostapd_rx_req_get_sta_settings;
ctx->rx_req_set_sta_settings = hostapd_rx_req_set_sta_settings;
ctx->rx_req_del_sta_settings = hostapd_rx_req_del_sta_settings;
ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
ctx->rx_req_set_selected_registrar =
hostapd_rx_req_set_selected_registrar;
ctx->rx_req_reboot_ap = hostapd_rx_req_reboot_ap;
ctx->rx_req_reset_ap = hostapd_rx_req_reset_ap;
ctx->rx_req_reboot_sta = hostapd_rx_req_reboot_sta;
ctx->rx_req_reset_sta = hostapd_rx_req_reset_sta;
hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd);
if (hapd->wps_upnp == NULL) {
os_free(ctx);
return -1;
}
wps->wps_upnp = hapd->wps_upnp;
if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
upnp_wps_device_deinit(hapd->wps_upnp);
hapd->wps_upnp = NULL;
return -1;
}
return 0;
}
static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
{
upnp_wps_device_deinit(hapd->wps_upnp);
}
#endif /* CONFIG_WPS_UPNP */

48
hostapd/wps_hostapd.h Normal file
View File

@ -0,0 +1,48 @@
/*
* hostapd / WPS integration
* Copyright (c) 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.
*/
#ifndef WPS_HOSTAPD_H
#define WPS_HOSTAPD_H
#ifdef CONFIG_WPS
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf);
void hostapd_deinit_wps(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
const char *pin);
int hostapd_wps_button_pushed(struct hostapd_data *hapd);
void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ie_len);
#else /* CONFIG_WPS */
static inline int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf)
{
return 0;
}
static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
{
}
static inline void hostapd_wps_probe_req_rx(struct hostapd_data *hapd,
const u8 *addr,
const u8 *ie, size_t ie_len)
{
}
#endif /* CONFIG_WPS */
#endif /* WPS_HOSTAPD_H */

View File

@ -0,0 +1,429 @@
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
--- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
--- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
--- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700
+++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.000000000 -0700
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
--- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700
+++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700
@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
}
*(p++)=0; /* Add the NULL method */
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
SSL_COMP *comp;
@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
--- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700
+++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700
@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
--- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.000000000 -0700
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
--- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
+++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
@@ -340,6 +340,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
--- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700
+++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.000000000 -0700
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
--- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.000000000 -0700
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
--- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700
+++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700
@@ -131,6 +131,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
--- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
+++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
@@ -282,6 +282,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
--- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
+++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700
@@ -226,3 +226,6 @@ DTLSv1_server_method
SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
SSL_SESSION_get_id 277 EXIST::FUNCTION:
+SSL_set_hello_extension 278 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
+SSL_set_session_secret_cb 280 EXIST::FUNCTION:

View File

@ -0,0 +1,429 @@
This patch is adding support for TLS hello extensions and externally
generated pre-shared key material to OpenSSL 0.9.8d. This is
based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h
--- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
+++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
@@ -345,6 +345,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -973,6 +976,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h
--- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
+++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
@@ -296,6 +296,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile
--- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
+++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800
@@ -24,7 +24,7 @@ LIBSRC= \
s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
+ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
d1_both.c d1_enc.c \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
@@ -35,7 +35,7 @@ LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
+ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
d1_both.o d1_enc.o \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
+t1_ext.o: t1_ext.c ssl_locl.h
diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c
--- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800
+++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800
@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
#endif
*(p++)=0; /* Add the NULL method */
+ /* send client hello extensions if any */
+ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
+ // set the total extensions length
+ s2n(s->tls_extension->length + 4, p);
+
+ // put the extensions with type and length
+ s2n(s->tls_extension->type, p);
+ s2n(s->tls_extension->length, p);
+
+ memcpy(p, s->tls_extension->data, s->tls_extension->length);
+ p+=s->tls_extension->length;
+ }
+
l=(p-d);
d=buf;
*(d++)=SSL3_MT_CLIENT_HELLO;
@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
unsigned char *p,*d;
- int i,al,ok;
+ int i,al,ok,pre_shared;
unsigned int j;
long n;
#ifndef OPENSSL_NO_COMP
@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
- if (j != 0 && j == s->session->session_id_length
+ /* check if we want to resume the session based on external pre-shared secret */
+ pre_shared = 0;
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
+ s->session->session_id_length = j;
+ memcpy(s->session->session_id, p, j);
+ pre_shared = 1;
+ }
+ }
+
+ if ((pre_shared || j != 0) && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
if(s->sid_ctx_length != s->session->sid_ctx_length
diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c
--- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700
+++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800
@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s)
}
#endif
+ /* Check for TLS client hello extension here */
+ if (p < (d+n) && s->version >= TLS1_VERSION)
+ {
+ if (s->tls_extension_cb)
+ {
+ TLS_EXTENSION tls_ext;
+ unsigned short ext_total_len;
+
+ n2s(p, ext_total_len);
+ n2s(p, tls_ext.type);
+ n2s(p, tls_ext.length);
+
+ // sanity check in TLS extension len
+ if (tls_ext.length > (d+n) - p)
+ {
+ // just cut the lenth to packet border
+ tls_ext.length = (d+n) - p;
+ }
+
+ tls_ext.data = p;
+
+ // returns an alert code or 0
+ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
+ if (al != 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
+ goto f_err;
+ }
+ }
+ }
+
+ /* Check if we want to use external pre-shared secret for this handshake */
+ /* for not reused session only */
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
+ {
+ s->hit=1;
+ s->session->ciphers=ciphers;
+ s->session->verify_result=X509_V_OK;
+
+ ciphers=NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+ if (pref_cipher == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher=pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
+
/* Given s->session->ciphers and SSL_get_ciphers, we must
* pick a cipher */
diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h
--- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
+++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
@@ -345,6 +345,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_extension_st TLS_EXTENSION;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
@@ -973,6 +976,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
+ /* TLS externsions */
+ TLS_EXTENSION *tls_extension;
+ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
+ void *tls_extension_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
};
#ifdef __cplusplus
@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
+/* TLS extensions functions */
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
+
/* BEGIN ERROR CODES */
/* The following lines are auto generated by the script mkerr.pl. Any changes
* made after this point may be overwritten when the script is next run.
@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_TLS1_ENC 210
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_HELLO_EXTENSION 213
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c
--- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800
+++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800
@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
{0,NULL}
};
diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c
--- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800
+++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800
@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL) return(0);
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return(1);
+}
+
typedef struct timeout_param_st
{
SSL_CTX *ctx;
diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c
--- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
+++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800
@@ -0,0 +1,48 @@
+
+#include <stdio.h>
+#include "ssl_locl.h"
+
+
+int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ s->tls_extension = NULL;
+ }
+
+ if(ext_data)
+ {
+ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
+ if(!s->tls_extension)
+ {
+ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ s->tls_extension->type = ext_type;
+ s->tls_extension->length = ext_len;
+ s->tls_extension->data = s->tls_extension + 1;
+ memcpy(s->tls_extension->data, ext_data, ext_len);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
+{
+ if(s->version >= TLS1_VERSION)
+ {
+ s->tls_extension_cb = cb;
+ s->tls_extension_cb_arg = arg;
+
+ return 1;
+ }
+
+ return 0;
+}
diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c
--- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700
+++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800
@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+ if(s->tls_extension)
+ {
+ OPENSSL_free(s->tls_extension);
+ }
ssl3_free(s);
}
diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h
--- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
+++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
@@ -296,6 +296,14 @@ extern "C" {
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
+/* TLS extension struct */
+struct tls_extension_st
+{
+ unsigned short type;
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num
--- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
+++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800
@@ -226,3 +226,6 @@ DTLSv1_server_method
SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
SSL_SESSION_get_id 277 EXIST::FUNCTION:
+SSL_set_hello_extension 278 EXIST::FUNCTION:
+SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
+SSL_set_session_secret_cb 280 EXIST::FUNCTION:

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