import wpa_supplicant+hostapd 0.6.8
This commit is contained in:
commit
c164510d5a
340
COPYING
Normal file
340
COPYING
Normal 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
19
README
Normal 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
7
hostapd/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
*.d
|
||||||
|
.config
|
||||||
|
driver_conf.c
|
||||||
|
hostapd
|
||||||
|
hostapd_cli
|
||||||
|
hlr_auc_gw
|
||||||
|
nt_password_hash
|
565
hostapd/ChangeLog
Normal file
565
hostapd/ChangeLog
Normal 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
602
hostapd/Makefile
Normal 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
390
hostapd/README
Normal 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
232
hostapd/README-WPS
Normal 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
510
hostapd/accounting.c
Normal 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
26
hostapd/accounting.h
Normal 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
139
hostapd/ap.h
Normal 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
501
hostapd/ap_list.c
Normal 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
71
hostapd/ap_list.h
Normal 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
467
hostapd/beacon.c
Normal 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
24
hostapd/beacon.h
Normal 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
2617
hostapd/config.c
Normal file
File diff suppressed because it is too large
Load Diff
415
hostapd/config.h
Normal file
415
hostapd/config.h
Normal 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
560
hostapd/ctrl_iface.c
Normal 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
21
hostapd/ctrl_iface.h
Normal 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
144
hostapd/defconfig
Normal 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
4
hostapd/doc/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
html
|
||||||
|
latex
|
||||||
|
hostapd.eps
|
||||||
|
hostapd.png
|
5
hostapd/doc/code_structure.doxygen
Normal file
5
hostapd/doc/code_structure.doxygen
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
\page code_structure Structure of the source code
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
66
hostapd/doc/ctrl_iface.doxygen
Normal file
66
hostapd/doc/ctrl_iface.doxygen
Normal 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
238
hostapd/doc/doxygen.fast
Normal 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
238
hostapd/doc/doxygen.full
Normal 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
|
20
hostapd/doc/driver_wrapper.doxygen
Normal file
20
hostapd/doc/driver_wrapper.doxygen
Normal 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
56
hostapd/doc/eap.doxygen
Normal 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
264
hostapd/doc/hostapd.fig
Normal 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
129
hostapd/doc/kerneldoc2doxygen.pl
Executable 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 $_;
|
||||||
|
|
52
hostapd/doc/mainpage.doxygen
Normal file
52
hostapd/doc/mainpage.doxygen
Normal 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
|
||||||
|
|
||||||
|
*/
|
5
hostapd/doc/porting.doxygen
Normal file
5
hostapd/doc/porting.doxygen
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
\page porting Porting to different target boards and operating systems
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
798
hostapd/driver.h
Normal file
798
hostapd/driver.h
Normal 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(¶ms, 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, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
838
hostapd/driver_bsd.c
Normal 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
1279
hostapd/driver_hostap.c
Normal file
File diff suppressed because it is too large
Load Diff
1483
hostapd/driver_madwifi.c
Normal file
1483
hostapd/driver_madwifi.c
Normal file
File diff suppressed because it is too large
Load Diff
2696
hostapd/driver_nl80211.c
Normal file
2696
hostapd/driver_nl80211.c
Normal file
File diff suppressed because it is too large
Load Diff
62
hostapd/driver_none.c
Normal file
62
hostapd/driver_none.c
Normal 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
1091
hostapd/driver_prism54.c
Normal file
File diff suppressed because it is too large
Load Diff
1300
hostapd/driver_test.c
Normal file
1300
hostapd/driver_test.c
Normal file
File diff suppressed because it is too large
Load Diff
372
hostapd/driver_wired.c
Normal file
372
hostapd/driver_wired.c
Normal 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
71
hostapd/drivers.c
Normal 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
77
hostapd/eap_testing.txt
Normal 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
1342
hostapd/eapol_sm.c
Normal file
File diff suppressed because it is too large
Load Diff
260
hostapd/eapol_sm.h
Normal file
260
hostapd/eapol_sm.h
Normal 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
216
hostapd/hostap_common.h
Normal 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
59
hostapd/hostapd.8
Normal 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
6
hostapd/hostapd.accept
Normal 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
2027
hostapd/hostapd.c
Normal file
File diff suppressed because it is too large
Load Diff
1024
hostapd/hostapd.conf
Normal file
1024
hostapd/hostapd.conf
Normal file
File diff suppressed because it is too large
Load Diff
5
hostapd/hostapd.deny
Normal file
5
hostapd/hostapd.deny
Normal 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
91
hostapd/hostapd.eap_user
Normal 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
238
hostapd/hostapd.h
Normal 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 */
|
4
hostapd/hostapd.radius_clients
Normal file
4
hostapd/hostapd.radius_clients
Normal 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
9
hostapd/hostapd.sim_db
Normal 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
9
hostapd/hostapd.vlan
Normal 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
9
hostapd/hostapd.wpa_psk
Normal 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
83
hostapd/hostapd_cli.1
Normal 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
673
hostapd/hostapd_cli.c
Normal 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
487
hostapd/hw_features.c
Normal 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
62
hostapd/hw_features.h
Normal 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
553
hostapd/iapp.c
Normal 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
54
hostapd/iapp.h
Normal 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
1768
hostapd/ieee802_11.c
Normal file
File diff suppressed because it is too large
Load Diff
56
hostapd/ieee802_11.h
Normal file
56
hostapd/ieee802_11.h
Normal 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
523
hostapd/ieee802_11_auth.c
Normal 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
33
hostapd/ieee802_11_auth.h
Normal 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
2042
hostapd/ieee802_1x.c
Normal file
File diff suppressed because it is too large
Load Diff
90
hostapd/ieee802_1x.h
Normal file
90
hostapd/ieee802_1x.h
Normal 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
9
hostapd/logwatch/README
Normal 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
65
hostapd/logwatch/hostapd
Executable 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);
|
10
hostapd/logwatch/hostapd.conf
Normal file
10
hostapd/logwatch/hostapd.conf
Normal 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
180
hostapd/mlme.c
Normal 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
40
hostapd/mlme.h
Normal 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 */
|
52
hostapd/nt_password_hash.c
Normal file
52
hostapd/nt_password_hash.c
Normal 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
402
hostapd/peerkey.c
Normal 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
455
hostapd/pmksa_cache.c
Normal 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
62
hostapd/pmksa_cache.h
Normal 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
275
hostapd/preauth.c
Normal 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
58
hostapd/preauth.h
Normal 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
177
hostapd/prism54.h
Normal 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
71
hostapd/priv_netlink.h
Normal 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
287
hostapd/radiotap.c
Normal 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
242
hostapd/radiotap.h
Normal 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
41
hostapd/radiotap_iter.h
Normal 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
711
hostapd/sta_info.c
Normal 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
43
hostapd/sta_info.h
Normal 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
826
hostapd/vlan_init.c
Normal 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
31
hostapd/vlan_init.h
Normal 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
40
hostapd/wired.conf
Normal 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
262
hostapd/wme.c
Normal 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
129
hostapd/wme.h
Normal 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
2447
hostapd/wpa.c
Normal file
File diff suppressed because it is too large
Load Diff
284
hostapd/wpa.h
Normal file
284
hostapd/wpa.h
Normal 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
221
hostapd/wpa_auth_i.h
Normal 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
864
hostapd/wpa_auth_ie.c
Normal 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
54
hostapd/wpa_auth_ie.h
Normal 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
1499
hostapd/wpa_ft.c
Normal file
File diff suppressed because it is too large
Load Diff
998
hostapd/wps_hostapd.c
Normal file
998
hostapd/wps_hostapd.c
Normal 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
48
hostapd/wps_hostapd.h
Normal 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 */
|
429
patches/openssl-0.9.8-tls-extensions.patch
Normal file
429
patches/openssl-0.9.8-tls-extensions.patch
Normal 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:
|
429
patches/openssl-0.9.8d-tls-extensions.patch
Normal file
429
patches/openssl-0.9.8d-tls-extensions.patch
Normal 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
Loading…
x
Reference in New Issue
Block a user