mirror of
https://github.com/lwfinger/rtl8188eu.git
synced 2024-11-09 23:19:39 +00:00
rtl8188eu: Update hostapd to version 2.9
These changed update the built-in version of hostapd from v0.8 to 2.9. The rtl871xdrv driver comes from git://github.com/pritambaral/hostapd-rtl871xdrv.git whose included patch has been applied to the standard source code. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
This commit is contained in:
parent
373d98d270
commit
a69d6361ef
873 changed files with 251278 additions and 91806 deletions
59
control_ap
59
control_ap
|
@ -32,9 +32,9 @@ esac
|
|||
# Symbols for needed programs
|
||||
|
||||
IPTABLES=/sbin/iptables
|
||||
IFCONFIG=/sbin/ifconfig
|
||||
DHCPD=/usr/sbin/dhcpd
|
||||
HOSTAPD=/home/finger/rtl8188eu/hostapd-0.8/hostapd/hostapd
|
||||
IFCONFIG=/usr/bin/ifconfig
|
||||
DHCPD=/sbin/dhcpd
|
||||
HOSTAPD=/home/finger/rtl8188eu/hostapd-2.9/hostapd/hostapd
|
||||
|
||||
# Symbols for AP and external interfaces
|
||||
|
||||
|
@ -80,31 +80,30 @@ start)
|
|||
touch /var/lib/dhcp/db/dhcpd.leases
|
||||
fi
|
||||
# Write the DHCP server configuration file
|
||||
echo "option domain-name-servers $NAME_SERVER;" > ~/dhcpd.conf
|
||||
echo "default-lease-time 600;" >> ~/dhcpd.conf
|
||||
echo "max-lease-time 7200;" >> ~/dhcpd.conf
|
||||
echo "ddns-update-style none; ddns-updates off;" >> ~/dhcpd.conf
|
||||
echo "subnet $AP_ADDR.0 netmask 255.255.255.0 {" >> ~/dhcpd.conf
|
||||
echo " range $AP_ADDR.200 $AP_ADDR.229;" >> ~/dhcpd.conf
|
||||
echo " option subnet-mask 255.255.255.0;" >> ~/dhcpd.conf
|
||||
echo " option broadcast-address $AP_ADDR.255;" >> ~/dhcpd.conf
|
||||
echo " option routers $AP_ADDR.1;" >> ~/dhcpd.conf
|
||||
echo "}" >> ~/dhcpd.conf
|
||||
echo "option domain-name-servers $NAME_SERVER;" > dhcpd.conf
|
||||
echo "default-lease-time 600;" >> dhcpd.conf
|
||||
echo "ddns-update-style none; ddns-updates off;" >> dhcpd.conf
|
||||
echo "subnet $AP_ADDR.0 netmask 255.255.255.0 {" >> dhcpd.conf
|
||||
echo " max-lease-time 7200;" >> dhcpd.conf
|
||||
echo " range $AP_ADDR.200 $AP_ADDR.229;" >> dhcpd.conf
|
||||
echo " option subnet-mask 255.255.255.0;" >> dhcpd.conf
|
||||
echo " option broadcast-address $AP_ADDR.255;" >> dhcpd.conf
|
||||
echo " option routers $AP_ADDR.1;" >> dhcpd.conf
|
||||
echo "}" >> dhcpd.conf
|
||||
# Bring up the DHCP server
|
||||
$DHCPD -cf ~/dhcpd.conf $NET_AP
|
||||
$DHCPD -cf dhcpd.conf $NET_AP
|
||||
# Write the hostapd configuration file
|
||||
cat > ~/hostapd.conf << EOF
|
||||
cat > hostapd << EOF
|
||||
auth_algs=1
|
||||
beacon_int=100
|
||||
country_code=US
|
||||
ctrl_interface_group=0
|
||||
ctrl_interface=/var/run/hostapd
|
||||
dtim_period=2
|
||||
dump_file=/tmp/hostapd.dump
|
||||
fragm_threshold=2346
|
||||
#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40][MAX-AMSDU-7935][DSSS_CCK-40]
|
||||
#ieee80211d=1
|
||||
ieee80211n=1
|
||||
#ieee80211n=1
|
||||
ignore_broadcast_ssid=0
|
||||
logger_stdout=-1
|
||||
logger_stdout_level=2
|
||||
|
@ -135,27 +134,27 @@ wmm_ac_vo_cwmin=2
|
|||
wmm_ac_vo_txop_limit=47
|
||||
wmm_enabled=1
|
||||
EOF
|
||||
echo "interface=$NET_AP" >> ~/hostapd.conf
|
||||
echo "ssid=$AP_SSID" >> ~/hostapd.conf
|
||||
echo "driver=$DRIVER" >> ~/hostapd.conf
|
||||
echo "hw_mode=g" >> ~/hostapd.conf
|
||||
echo "channel=$AP_CHANNEL" >> ~/hostapd.conf
|
||||
echo "wpa=$ENCRYPT_MODE" >> ~/hostapd.conf
|
||||
echo "wpa_key_mgmt=WPA-PSK" >> ~/hostapd.conf
|
||||
echo "wpa_pairwise=TKIP CCMP" >> ~/hostapd.conf
|
||||
echo "rsn_pairwise=CCMP" >> ~/hostapd.conf
|
||||
echo "wpa_passphrase=$WPA_SECRET" >> ~/hostapd.conf
|
||||
echo "interface=$NET_AP" >> hostapd
|
||||
echo "ssid=$AP_SSID" >> hostapd
|
||||
echo "driver=$DRIVER" >> hostapd
|
||||
echo "hw_mode=g" >> hostapd
|
||||
echo "channel=$AP_CHANNEL" >> hostapd
|
||||
echo "wpa=$ENCRYPT_MODE" >> hostapd
|
||||
echo "wpa_key_mgmt=WPA-PSK" >> hostapd
|
||||
echo "wpa_pairwise=TKIP CCMP" >> hostapd
|
||||
echo "rsn_pairwise=CCMP" >> hostapd
|
||||
echo "wpa_passphrase=$WPA_SECRET" >> hostapd
|
||||
# Enable packet forwarding
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
# Bring up hostapd
|
||||
$HOSTAPD -dd -B ~/hostapd.conf
|
||||
$HOSTAPD -dd -B hostapd
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping AP mode"
|
||||
# Stop hostapd and dhcpd daemons
|
||||
killall hostapd
|
||||
killall dhcpd
|
||||
rm -f ~/hostapd.conf
|
||||
rm -f ~/dhcpd.conf
|
||||
rm -f hostapd
|
||||
rm -f dhcpd.conf
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -1,340 +0,0 @@
|
|||
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.
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* hostapd / Configuration file parser
|
||||
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_FILE_H
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
|
||||
#endif /* CONFIG_FILE_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* hostapd / State dump
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "radius/radius_server.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "dump_state.h"
|
||||
|
||||
|
||||
static void fprint_char(FILE *f, char c)
|
||||
{
|
||||
if (c >= 32 && c < 127)
|
||||
fprintf(f, "%c", c);
|
||||
else
|
||||
fprintf(f, "<%02x>", c);
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_dump_state(FILE *f, const char *prefix,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
fprintf(f, "%sIEEE 802.1X:\n", prefix);
|
||||
|
||||
if (sm->identity) {
|
||||
size_t i;
|
||||
fprintf(f, "%sidentity=", prefix);
|
||||
for (i = 0; i < sm->identity_len; i++)
|
||||
fprint_char(f, sm->identity[i]);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
|
||||
"Supplicant: %d (%s)\n", prefix,
|
||||
sm->eap_type_authsrv,
|
||||
eap_server_get_name(0, sm->eap_type_authsrv),
|
||||
sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
|
||||
|
||||
fprintf(f, "%scached_packets=%s\n", prefix,
|
||||
sm->last_recv_radius ? "[RX RADIUS]" : "");
|
||||
|
||||
eapol_auth_dump_state(f, prefix, sm);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
|
||||
*/
|
||||
static void hostapd_dump_state(struct hostapd_data *hapd)
|
||||
{
|
||||
FILE *f;
|
||||
time_t now;
|
||||
struct sta_info *sta;
|
||||
int i;
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
char *buf;
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
if (!hapd->conf->dump_log_name) {
|
||||
wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
|
||||
"request");
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
|
||||
hapd->conf->dump_log_name);
|
||||
f = fopen(hapd->conf->dump_log_name, "w");
|
||||
if (f == NULL) {
|
||||
wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
|
||||
"writing.", hapd->conf->dump_log_name);
|
||||
return;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
fprintf(f, "hostapd state dump - %s", ctime(&now));
|
||||
fprintf(f, "num_sta=%d num_sta_non_erp=%d "
|
||||
"num_sta_no_short_slot_time=%d\n"
|
||||
"num_sta_no_short_preamble=%d\n",
|
||||
hapd->num_sta, hapd->iface->num_sta_non_erp,
|
||||
hapd->iface->num_sta_no_short_slot_time,
|
||||
hapd->iface->num_sta_no_short_preamble);
|
||||
|
||||
for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
|
||||
fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
|
||||
|
||||
fprintf(f,
|
||||
" AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
|
||||
" capability=0x%x listen_interval=%d\n",
|
||||
sta->aid,
|
||||
sta->flags,
|
||||
(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
|
||||
(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
|
||||
(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
|
||||
(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
|
||||
(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
|
||||
(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
|
||||
(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
|
||||
""),
|
||||
(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
|
||||
"[SHORT_PREAMBLE]" : ""),
|
||||
(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
|
||||
(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
|
||||
(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
|
||||
(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
|
||||
(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
|
||||
(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
|
||||
(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
|
||||
sta->capability,
|
||||
sta->listen_interval);
|
||||
|
||||
fprintf(f, " supported_rates=");
|
||||
for (i = 0; i < sta->supported_rates_len; i++)
|
||||
fprintf(f, "%02x ", sta->supported_rates[i]);
|
||||
fprintf(f, "\n");
|
||||
|
||||
fprintf(f,
|
||||
" timeout_next=%s\n",
|
||||
(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
|
||||
(sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
|
||||
"DEAUTH")));
|
||||
|
||||
ieee802_1x_dump_state(f, " ", sta);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
buf = os_malloc(4096);
|
||||
if (buf) {
|
||||
int count = radius_client_get_mib(hapd->radius, buf, 4096);
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > 4095)
|
||||
count = 4095;
|
||||
buf[count] = '\0';
|
||||
fprintf(f, "%s", buf);
|
||||
|
||||
#ifdef RADIUS_SERVER
|
||||
count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > 4095)
|
||||
count = 4095;
|
||||
buf[count] = '\0';
|
||||
fprintf(f, "%s", buf);
|
||||
#endif /* RADIUS_SERVER */
|
||||
|
||||
os_free(buf);
|
||||
}
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
hostapd_dump_state(iface->bss[i]);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* hostapd / State dump
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef DUMP_STATE_H
|
||||
#define DUMP_STATE_H
|
||||
|
||||
int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
|
||||
|
||||
#endif /* DUMP_STATE_H */
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* EAP method registration
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_REGISTER_H
|
||||
#define EAP_REGISTER_H
|
||||
|
||||
int eap_server_register_methods(void);
|
||||
|
||||
#endif /* EAP_REGISTER_H */
|
|
@ -1,715 +0,0 @@
|
|||
/*
|
||||
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
|
||||
* Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*
|
||||
* This is an example implementation of the EAP-SIM/AKA database/authentication
|
||||
* gateway interface to HLR/AuC. It is expected to be replaced with an
|
||||
* implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
|
||||
* a local implementation of SIM triplet and AKA authentication data generator.
|
||||
*
|
||||
* hostapd will send SIM/AKA authentication queries over a UNIX domain socket
|
||||
* to and external program, e.g., this hlr_auc_gw. This interface uses simple
|
||||
* text-based format:
|
||||
*
|
||||
* EAP-SIM / GSM triplet query/response:
|
||||
* SIM-REQ-AUTH <IMSI> <max_chal>
|
||||
* SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
|
||||
* SIM-RESP-AUTH <IMSI> FAILURE
|
||||
*
|
||||
* EAP-AKA / UMTS query/response:
|
||||
* AKA-REQ-AUTH <IMSI>
|
||||
* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
|
||||
* AKA-RESP-AUTH <IMSI> FAILURE
|
||||
*
|
||||
* EAP-AKA / UMTS AUTS (re-synchronization):
|
||||
* AKA-AUTS <IMSI> <AUTS> <RAND>
|
||||
*
|
||||
* IMSI and max_chal are sent as an ASCII string,
|
||||
* Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
|
||||
*
|
||||
* The example implementation here reads GSM authentication triplets from a
|
||||
* text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
|
||||
* strings. This is used to simulate an HLR/AuC. As such, it is not very useful
|
||||
* for real life authentication, but it is useful both as an example
|
||||
* implementation and for EAP-SIM testing.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/milenage.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
|
||||
static const char *socket_path;
|
||||
static int serv_sock = -1;
|
||||
|
||||
/* GSM triplets */
|
||||
struct gsm_triplet {
|
||||
struct gsm_triplet *next;
|
||||
char imsi[20];
|
||||
u8 kc[8];
|
||||
u8 sres[4];
|
||||
u8 _rand[16];
|
||||
};
|
||||
|
||||
static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
|
||||
|
||||
/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
|
||||
struct milenage_parameters {
|
||||
struct milenage_parameters *next;
|
||||
char imsi[20];
|
||||
u8 ki[16];
|
||||
u8 opc[16];
|
||||
u8 amf[2];
|
||||
u8 sqn[6];
|
||||
};
|
||||
|
||||
static struct milenage_parameters *milenage_db = NULL;
|
||||
|
||||
#define EAP_SIM_MAX_CHAL 3
|
||||
|
||||
#define EAP_AKA_RAND_LEN 16
|
||||
#define EAP_AKA_AUTN_LEN 16
|
||||
#define EAP_AKA_AUTS_LEN 14
|
||||
#define EAP_AKA_RES_MAX_LEN 16
|
||||
#define EAP_AKA_IK_LEN 16
|
||||
#define EAP_AKA_CK_LEN 16
|
||||
|
||||
|
||||
static int open_socket(const char *path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket(PF_UNIX)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
perror("bind(PF_UNIX)");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static int read_gsm_triplets(const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[200], *pos, *pos2;
|
||||
struct gsm_triplet *g = NULL;
|
||||
int line, ret = 0;
|
||||
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
printf("Could not open GSM tripler data file '%s'\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
line = 0;
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
line++;
|
||||
|
||||
/* Parse IMSI:Kc:SRES:RAND */
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
pos = buf;
|
||||
while (*pos != '\0' && *pos != '\n')
|
||||
pos++;
|
||||
if (*pos == '\n')
|
||||
*pos = '\0';
|
||||
pos = buf;
|
||||
if (*pos == '\0')
|
||||
continue;
|
||||
|
||||
g = os_zalloc(sizeof(*g));
|
||||
if (g == NULL) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* IMSI */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) >= sizeof(g->imsi)) {
|
||||
printf("%s:%d - Too long IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
os_strlcpy(g->imsi, pos, sizeof(g->imsi));
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* Kc */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
|
||||
printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* SRES */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid SRES (%s)\n", fname, line,
|
||||
pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
|
||||
printf("%s:%d - Invalid SRES (%s)\n", fname, line,
|
||||
pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* RAND */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2)
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
|
||||
printf("%s:%d - Invalid RAND (%s)\n", fname, line,
|
||||
pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
g->next = gsm_db;
|
||||
gsm_db = g;
|
||||
g = NULL;
|
||||
}
|
||||
free(g);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct gsm_triplet * get_gsm_triplet(const char *imsi)
|
||||
{
|
||||
struct gsm_triplet *g = gsm_db_pos;
|
||||
|
||||
while (g) {
|
||||
if (strcmp(g->imsi, imsi) == 0) {
|
||||
gsm_db_pos = g->next;
|
||||
return g;
|
||||
}
|
||||
g = g->next;
|
||||
}
|
||||
|
||||
g = gsm_db;
|
||||
while (g && g != gsm_db_pos) {
|
||||
if (strcmp(g->imsi, imsi) == 0) {
|
||||
gsm_db_pos = g->next;
|
||||
return g;
|
||||
}
|
||||
g = g->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int read_milenage(const char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[200], *pos, *pos2;
|
||||
struct milenage_parameters *m = NULL;
|
||||
int line, ret = 0;
|
||||
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
printf("Could not open Milenage data file '%s'\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
line = 0;
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
line++;
|
||||
|
||||
/* Parse IMSI Ki OPc AMF SQN */
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
pos = buf;
|
||||
while (*pos != '\0' && *pos != '\n')
|
||||
pos++;
|
||||
if (*pos == '\n')
|
||||
*pos = '\0';
|
||||
pos = buf;
|
||||
if (*pos == '\0')
|
||||
continue;
|
||||
|
||||
m = os_zalloc(sizeof(*m));
|
||||
if (m == NULL) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* IMSI */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) >= sizeof(m->imsi)) {
|
||||
printf("%s:%d - Too long IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
os_strlcpy(m->imsi, pos, sizeof(m->imsi));
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* Ki */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
|
||||
printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* OPc */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
|
||||
printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* AMF */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
|
||||
printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* SQN */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2)
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
|
||||
printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
m->next = milenage_db;
|
||||
milenage_db = m;
|
||||
m = NULL;
|
||||
}
|
||||
free(m);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct milenage_parameters * get_milenage(const char *imsi)
|
||||
{
|
||||
struct milenage_parameters *m = milenage_db;
|
||||
|
||||
while (m) {
|
||||
if (strcmp(m->imsi, imsi) == 0)
|
||||
break;
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
||||
char *imsi)
|
||||
{
|
||||
int count, max_chal, ret;
|
||||
char *pos;
|
||||
char reply[1000], *rpos, *rend;
|
||||
struct milenage_parameters *m;
|
||||
struct gsm_triplet *g;
|
||||
|
||||
reply[0] = '\0';
|
||||
|
||||
pos = strchr(imsi, ' ');
|
||||
if (pos) {
|
||||
*pos++ = '\0';
|
||||
max_chal = atoi(pos);
|
||||
if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
|
||||
max_chal = EAP_SIM_MAX_CHAL;
|
||||
} else
|
||||
max_chal = EAP_SIM_MAX_CHAL;
|
||||
|
||||
rend = &reply[sizeof(reply)];
|
||||
rpos = reply;
|
||||
ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
|
||||
if (ret < 0 || ret >= rend - rpos)
|
||||
return;
|
||||
rpos += ret;
|
||||
|
||||
m = get_milenage(imsi);
|
||||
if (m) {
|
||||
u8 _rand[16], sres[4], kc[8];
|
||||
for (count = 0; count < max_chal; count++) {
|
||||
if (random_get_bytes(_rand, 16) < 0)
|
||||
return;
|
||||
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
|
||||
*rpos++ = ' ';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
|
||||
*rpos++ = ':';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
|
||||
*rpos++ = ':';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
|
||||
}
|
||||
*rpos = '\0';
|
||||
goto send;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while (count < max_chal && (g = get_gsm_triplet(imsi))) {
|
||||
if (strcmp(g->imsi, imsi) != 0)
|
||||
continue;
|
||||
|
||||
if (rpos < rend)
|
||||
*rpos++ = ' ';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
|
||||
if (rpos < rend)
|
||||
*rpos++ = ':';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
|
||||
if (rpos < rend)
|
||||
*rpos++ = ':';
|
||||
rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
printf("No GSM triplets found for %s\n", imsi);
|
||||
ret = snprintf(rpos, rend - rpos, " FAILURE");
|
||||
if (ret < 0 || ret >= rend - rpos)
|
||||
return;
|
||||
rpos += ret;
|
||||
}
|
||||
|
||||
send:
|
||||
printf("Send: %s\n", reply);
|
||||
if (sendto(s, reply, rpos - reply, 0,
|
||||
(struct sockaddr *) from, fromlen) < 0)
|
||||
perror("send");
|
||||
}
|
||||
|
||||
|
||||
static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
||||
char *imsi)
|
||||
{
|
||||
/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
|
||||
char reply[1000], *pos, *end;
|
||||
u8 _rand[EAP_AKA_RAND_LEN];
|
||||
u8 autn[EAP_AKA_AUTN_LEN];
|
||||
u8 ik[EAP_AKA_IK_LEN];
|
||||
u8 ck[EAP_AKA_CK_LEN];
|
||||
u8 res[EAP_AKA_RES_MAX_LEN];
|
||||
size_t res_len;
|
||||
int ret;
|
||||
struct milenage_parameters *m;
|
||||
|
||||
m = get_milenage(imsi);
|
||||
if (m) {
|
||||
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
|
||||
return;
|
||||
res_len = EAP_AKA_RES_MAX_LEN;
|
||||
inc_byte_array(m->sqn, 6);
|
||||
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
|
||||
m->sqn[0], m->sqn[1], m->sqn[2],
|
||||
m->sqn[3], m->sqn[4], m->sqn[5]);
|
||||
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
|
||||
autn, ik, ck, res, &res_len);
|
||||
} else {
|
||||
printf("Unknown IMSI: %s\n", imsi);
|
||||
#ifdef AKA_USE_FIXED_TEST_VALUES
|
||||
printf("Using fixed test values for AKA\n");
|
||||
memset(_rand, '0', EAP_AKA_RAND_LEN);
|
||||
memset(autn, '1', EAP_AKA_AUTN_LEN);
|
||||
memset(ik, '3', EAP_AKA_IK_LEN);
|
||||
memset(ck, '4', EAP_AKA_CK_LEN);
|
||||
memset(res, '2', EAP_AKA_RES_MAX_LEN);
|
||||
res_len = EAP_AKA_RES_MAX_LEN;
|
||||
#else /* AKA_USE_FIXED_TEST_VALUES */
|
||||
return;
|
||||
#endif /* AKA_USE_FIXED_TEST_VALUES */
|
||||
}
|
||||
|
||||
pos = reply;
|
||||
end = &reply[sizeof(reply)];
|
||||
ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
|
||||
if (ret < 0 || ret >= end - pos)
|
||||
return;
|
||||
pos += ret;
|
||||
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
|
||||
*pos++ = ' ';
|
||||
pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
|
||||
*pos++ = ' ';
|
||||
pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
|
||||
*pos++ = ' ';
|
||||
pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
|
||||
*pos++ = ' ';
|
||||
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
|
||||
|
||||
printf("Send: %s\n", reply);
|
||||
|
||||
if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
|
||||
fromlen) < 0)
|
||||
perror("send");
|
||||
}
|
||||
|
||||
|
||||
static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
|
||||
char *imsi)
|
||||
{
|
||||
char *auts, *__rand;
|
||||
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
|
||||
struct milenage_parameters *m;
|
||||
|
||||
/* AKA-AUTS <IMSI> <AUTS> <RAND> */
|
||||
|
||||
auts = strchr(imsi, ' ');
|
||||
if (auts == NULL)
|
||||
return;
|
||||
*auts++ = '\0';
|
||||
|
||||
__rand = strchr(auts, ' ');
|
||||
if (__rand == NULL)
|
||||
return;
|
||||
*__rand++ = '\0';
|
||||
|
||||
printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
|
||||
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
|
||||
hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
|
||||
printf("Could not parse AUTS/RAND\n");
|
||||
return;
|
||||
}
|
||||
|
||||
m = get_milenage(imsi);
|
||||
if (m == NULL) {
|
||||
printf("Unknown IMSI: %s\n", imsi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
|
||||
printf("AKA-AUTS: Incorrect MAC-S\n");
|
||||
} else {
|
||||
memcpy(m->sqn, sqn, 6);
|
||||
printf("AKA-AUTS: Re-synchronized: "
|
||||
"SQN=%02x%02x%02x%02x%02x%02x\n",
|
||||
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int process(int s)
|
||||
{
|
||||
char buf[1000];
|
||||
struct sockaddr_un from;
|
||||
socklen_t fromlen;
|
||||
ssize_t res;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
|
||||
&fromlen);
|
||||
if (res < 0) {
|
||||
perror("recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
return 0;
|
||||
|
||||
if ((size_t) res >= sizeof(buf))
|
||||
res = sizeof(buf) - 1;
|
||||
buf[res] = '\0';
|
||||
|
||||
printf("Received: %s\n", buf);
|
||||
|
||||
if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
|
||||
sim_req_auth(s, &from, fromlen, buf + 13);
|
||||
else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
|
||||
aka_req_auth(s, &from, fromlen, buf + 13);
|
||||
else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
|
||||
aka_auts(s, &from, fromlen, buf + 9);
|
||||
else
|
||||
printf("Unknown request: %s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct gsm_triplet *g, *gprev;
|
||||
struct milenage_parameters *m, *prev;
|
||||
|
||||
g = gsm_db;
|
||||
while (g) {
|
||||
gprev = g;
|
||||
g = g->next;
|
||||
free(gprev);
|
||||
}
|
||||
|
||||
m = milenage_db;
|
||||
while (m) {
|
||||
prev = m;
|
||||
m = m->next;
|
||||
free(prev);
|
||||
}
|
||||
|
||||
close(serv_sock);
|
||||
unlink(socket_path);
|
||||
}
|
||||
|
||||
|
||||
static void handle_term(int sig)
|
||||
{
|
||||
printf("Signal %d - terminate\n", sig);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
|
||||
"database/authenticator\n"
|
||||
"Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>\n"
|
||||
"\n"
|
||||
"usage:\n"
|
||||
"hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
|
||||
"[-m<milenage file>]\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
" -h = show this usage help\n"
|
||||
" -s<socket path> = path for UNIX domain socket\n"
|
||||
" (default: %s)\n"
|
||||
" -g<triplet file> = path for GSM authentication triplets\n"
|
||||
" -m<milenage file> = path for Milenage keys\n",
|
||||
default_socket_path);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char *milenage_file = NULL;
|
||||
char *gsm_triplet_file = NULL;
|
||||
|
||||
socket_path = default_socket_path;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "g:hm:s:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'g':
|
||||
gsm_triplet_file = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
case 'm':
|
||||
milenage_file = optarg;
|
||||
break;
|
||||
case 's':
|
||||
socket_path = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
|
||||
return -1;
|
||||
|
||||
if (milenage_file && read_milenage(milenage_file) < 0)
|
||||
return -1;
|
||||
|
||||
serv_sock = open_socket(socket_path);
|
||||
if (serv_sock < 0)
|
||||
return -1;
|
||||
|
||||
printf("Listening for requests on %s\n", socket_path);
|
||||
|
||||
atexit(cleanup);
|
||||
signal(SIGTERM, handle_term);
|
||||
signal(SIGINT, handle_term);
|
||||
|
||||
for (;;)
|
||||
process(serv_sock);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,599 +0,0 @@
|
|||
/*
|
||||
* hostapd / main()
|
||||
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
#include <syslog.h>
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "common/version.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "eap_server/tncs.h"
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "config_file.h"
|
||||
#include "eap_register.h"
|
||||
#include "dump_state.h"
|
||||
#include "ctrl_iface.h"
|
||||
|
||||
|
||||
extern int wpa_debug_level;
|
||||
extern int wpa_debug_show_keys;
|
||||
extern int wpa_debug_timestamp;
|
||||
|
||||
|
||||
struct hapd_interfaces {
|
||||
size_t count;
|
||||
struct hostapd_iface **iface;
|
||||
};
|
||||
|
||||
|
||||
static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
int (*cb)(struct hostapd_iface *iface,
|
||||
void *ctx), void *ctx)
|
||||
{
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
ret = cb(interfaces->iface[i], ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_HOSTAPD_LOGGER
|
||||
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
|
||||
int level, const char *txt, size_t len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
char *format, *module_str;
|
||||
int maxlen;
|
||||
int conf_syslog_level, conf_stdout_level;
|
||||
unsigned int conf_syslog, conf_stdout;
|
||||
|
||||
maxlen = len + 100;
|
||||
format = os_malloc(maxlen);
|
||||
if (!format)
|
||||
return;
|
||||
|
||||
if (hapd && hapd->conf) {
|
||||
conf_syslog_level = hapd->conf->logger_syslog_level;
|
||||
conf_stdout_level = hapd->conf->logger_stdout_level;
|
||||
conf_syslog = hapd->conf->logger_syslog;
|
||||
conf_stdout = hapd->conf->logger_stdout;
|
||||
} else {
|
||||
conf_syslog_level = conf_stdout_level = 0;
|
||||
conf_syslog = conf_stdout = (unsigned int) -1;
|
||||
}
|
||||
|
||||
switch (module) {
|
||||
case HOSTAPD_MODULE_IEEE80211:
|
||||
module_str = "IEEE 802.11";
|
||||
break;
|
||||
case HOSTAPD_MODULE_IEEE8021X:
|
||||
module_str = "IEEE 802.1X";
|
||||
break;
|
||||
case HOSTAPD_MODULE_RADIUS:
|
||||
module_str = "RADIUS";
|
||||
break;
|
||||
case HOSTAPD_MODULE_WPA:
|
||||
module_str = "WPA";
|
||||
break;
|
||||
case HOSTAPD_MODULE_DRIVER:
|
||||
module_str = "DRIVER";
|
||||
break;
|
||||
case HOSTAPD_MODULE_IAPP:
|
||||
module_str = "IAPP";
|
||||
break;
|
||||
case HOSTAPD_MODULE_MLME:
|
||||
module_str = "MLME";
|
||||
break;
|
||||
default:
|
||||
module_str = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hapd && hapd->conf && addr)
|
||||
os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
|
||||
hapd->conf->iface, MAC2STR(addr),
|
||||
module_str ? " " : "", module_str, txt);
|
||||
else if (hapd && hapd->conf)
|
||||
os_snprintf(format, maxlen, "%s:%s%s %s",
|
||||
hapd->conf->iface, module_str ? " " : "",
|
||||
module_str, txt);
|
||||
else if (addr)
|
||||
os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
|
||||
MAC2STR(addr), module_str ? " " : "",
|
||||
module_str, txt);
|
||||
else
|
||||
os_snprintf(format, maxlen, "%s%s%s",
|
||||
module_str, module_str ? ": " : "", txt);
|
||||
|
||||
if ((conf_stdout & module) && level >= conf_stdout_level) {
|
||||
wpa_debug_print_timestamp();
|
||||
printf("%s\n", format);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
if ((conf_syslog & module) && level >= conf_syslog_level) {
|
||||
int priority;
|
||||
switch (level) {
|
||||
case HOSTAPD_LEVEL_DEBUG_VERBOSE:
|
||||
case HOSTAPD_LEVEL_DEBUG:
|
||||
priority = LOG_DEBUG;
|
||||
break;
|
||||
case HOSTAPD_LEVEL_INFO:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
case HOSTAPD_LEVEL_NOTICE:
|
||||
priority = LOG_NOTICE;
|
||||
break;
|
||||
case HOSTAPD_LEVEL_WARNING:
|
||||
priority = LOG_WARNING;
|
||||
break;
|
||||
default:
|
||||
priority = LOG_INFO;
|
||||
break;
|
||||
}
|
||||
syslog(priority, "%s", format);
|
||||
}
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
os_free(format);
|
||||
}
|
||||
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_init - Allocate and initialize per-interface data
|
||||
* @config_file: Path to the configuration file
|
||||
* Returns: Pointer to the allocated interface data or %NULL on failure
|
||||
*
|
||||
* This function is used to allocate main data structures for per-interface
|
||||
* data. The allocated data buffer will be freed by calling
|
||||
* hostapd_cleanup_iface().
|
||||
*/
|
||||
static struct hostapd_iface * hostapd_init(const char *config_file)
|
||||
{
|
||||
struct hostapd_iface *hapd_iface = NULL;
|
||||
struct hostapd_config *conf = NULL;
|
||||
struct hostapd_data *hapd;
|
||||
size_t i;
|
||||
|
||||
hapd_iface = os_zalloc(sizeof(*hapd_iface));
|
||||
if (hapd_iface == NULL)
|
||||
goto fail;
|
||||
|
||||
hapd_iface->reload_config = hostapd_reload_config;
|
||||
hapd_iface->config_read_cb = hostapd_config_read;
|
||||
hapd_iface->config_fname = os_strdup(config_file);
|
||||
if (hapd_iface->config_fname == NULL)
|
||||
goto fail;
|
||||
hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
|
||||
hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
|
||||
hapd_iface->for_each_interface = hostapd_for_each_interface;
|
||||
|
||||
conf = hostapd_config_read(hapd_iface->config_fname);
|
||||
if (conf == NULL)
|
||||
goto fail;
|
||||
hapd_iface->conf = conf;
|
||||
|
||||
hapd_iface->num_bss = conf->num_bss;
|
||||
hapd_iface->bss = os_zalloc(conf->num_bss *
|
||||
sizeof(struct hostapd_data *));
|
||||
if (hapd_iface->bss == NULL)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++) {
|
||||
hapd = hapd_iface->bss[i] =
|
||||
hostapd_alloc_bss_data(hapd_iface, conf,
|
||||
&conf->bss[i]);
|
||||
if (hapd == NULL)
|
||||
goto fail;
|
||||
hapd->msg_ctx = hapd;
|
||||
}
|
||||
|
||||
return hapd_iface;
|
||||
|
||||
fail:
|
||||
if (conf)
|
||||
hostapd_config_free(conf);
|
||||
if (hapd_iface) {
|
||||
os_free(hapd_iface->config_fname);
|
||||
os_free(hapd_iface->bss);
|
||||
os_free(hapd_iface);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
{
|
||||
struct wpa_init_params params;
|
||||
size_t i;
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
u8 *b = conf->bssid;
|
||||
struct wpa_driver_capa capa;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
|
||||
wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the driver interface */
|
||||
if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
|
||||
b = NULL;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.bssid = b;
|
||||
params.ifname = hapd->conf->iface;
|
||||
params.ssid = (const u8 *) hapd->conf->ssid.ssid;
|
||||
params.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
params.test_socket = hapd->conf->test_socket;
|
||||
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
|
||||
|
||||
params.num_bridge = hapd->iface->num_bss;
|
||||
params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
|
||||
if (params.bridge == NULL)
|
||||
return -1;
|
||||
for (i = 0; i < hapd->iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = hapd->iface->bss[i];
|
||||
if (bss->conf->bridge[0])
|
||||
params.bridge[i] = bss->conf->bridge;
|
||||
}
|
||||
|
||||
params.own_addr = hapd->own_addr;
|
||||
|
||||
hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms);
|
||||
os_free(params.bridge);
|
||||
if (hapd->drv_priv == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s driver initialization failed.",
|
||||
hapd->driver->name);
|
||||
hapd->driver = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->driver->get_capa &&
|
||||
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0)
|
||||
iface->drv_flags = capa.flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
|
||||
{
|
||||
const struct wpa_driver_ops *driver;
|
||||
void *drv_priv;
|
||||
if (iface == NULL)
|
||||
return;
|
||||
driver = iface->bss[0]->driver;
|
||||
drv_priv = iface->bss[0]->drv_priv;
|
||||
hostapd_interface_deinit(iface);
|
||||
if (driver && driver->hapd_deinit)
|
||||
driver->hapd_deinit(drv_priv);
|
||||
hostapd_interface_free(iface);
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_iface *
|
||||
hostapd_interface_init(struct hapd_interfaces *interfaces,
|
||||
const char *config_fname, int debug)
|
||||
{
|
||||
struct hostapd_iface *iface;
|
||||
int k;
|
||||
|
||||
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
|
||||
iface = hostapd_init(config_fname);
|
||||
if (!iface)
|
||||
return NULL;
|
||||
iface->interfaces = interfaces;
|
||||
|
||||
for (k = 0; k < debug; k++) {
|
||||
if (iface->bss[0]->conf->logger_stdout_level > 0)
|
||||
iface->bss[0]->conf->logger_stdout_level--;
|
||||
}
|
||||
|
||||
if (hostapd_driver_init(iface) ||
|
||||
hostapd_setup_interface(iface)) {
|
||||
hostapd_interface_deinit_free(iface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* handle_term - SIGINT and SIGTERM handler to terminate hostapd process
|
||||
*/
|
||||
static void handle_term(int sig, void *signal_ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
|
||||
eloop_terminate();
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
if (hostapd_reload_config(iface) < 0) {
|
||||
wpa_printf(MSG_WARNING, "Failed to read new configuration "
|
||||
"file - continuing with old.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* handle_reload - SIGHUP handler to reload configuration
|
||||
*/
|
||||
static void handle_reload(int sig, void *signal_ctx)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = signal_ctx;
|
||||
wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
|
||||
sig);
|
||||
hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void handle_dump_state(int sig, void *signal_ctx)
|
||||
{
|
||||
#ifdef HOSTAPD_DUMP_STATE
|
||||
struct hapd_interfaces *interfaces = signal_ctx;
|
||||
hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
|
||||
#endif /* HOSTAPD_DUMP_STATE */
|
||||
}
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
|
||||
static int hostapd_global_init(struct hapd_interfaces *interfaces)
|
||||
{
|
||||
hostapd_logger_register_cb(hostapd_logger_cb);
|
||||
|
||||
if (eap_server_register_methods()) {
|
||||
wpa_printf(MSG_ERROR, "Failed to register EAP methods");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eloop_init()) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
|
||||
return -1;
|
||||
}
|
||||
|
||||
random_init();
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
eloop_register_signal(SIGHUP, handle_reload, interfaces);
|
||||
eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
eloop_register_signal_terminate(handle_term, interfaces);
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
openlog("hostapd", 0, LOG_DAEMON);
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_global_deinit(const char *pid_file)
|
||||
{
|
||||
#ifdef EAP_SERVER_TNC
|
||||
tncs_global_deinit();
|
||||
#endif /* EAP_SERVER_TNC */
|
||||
|
||||
random_deinit();
|
||||
|
||||
eloop_destroy();
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
closelog();
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
eap_server_unregister_methods();
|
||||
|
||||
os_daemonize_terminate(pid_file);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
|
||||
const char *pid_file)
|
||||
{
|
||||
#ifdef EAP_SERVER_TNC
|
||||
int tnc = 0;
|
||||
size_t i, k;
|
||||
|
||||
for (i = 0; !tnc && i < ifaces->count; i++) {
|
||||
for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
|
||||
if (ifaces->iface[i]->bss[0]->conf->tnc) {
|
||||
tnc++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tnc && tncs_global_init() < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
|
||||
return -1;
|
||||
}
|
||||
#endif /* EAP_SERVER_TNC */
|
||||
|
||||
if (daemonize && os_daemonize(pid_file)) {
|
||||
perror("daemon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void show_version(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"hostapd v" VERSION_STR "\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
show_version();
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"usage: hostapd [-hdBKtv] [-P <PID file>] "
|
||||
"<configuration file(s)>\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
" -h show this usage\n"
|
||||
" -d show more debug messages (-dd for even more)\n"
|
||||
" -B run daemon in the background\n"
|
||||
" -P PID file\n"
|
||||
" -K include key data in debug messages\n"
|
||||
#ifdef CONFIG_DEBUG_FILE
|
||||
" -f log output to debug file instead of stdout\n"
|
||||
#endif /* CONFIG_DEBUG_FILE */
|
||||
" -t include timestamps in some debug messages\n"
|
||||
" -v show hostapd version\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static const char * hostapd_msg_ifname_cb(void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
if (hapd && hapd->iconf && hapd->iconf->bss)
|
||||
return hapd->iconf->bss->iface;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct hapd_interfaces interfaces;
|
||||
int ret = 1;
|
||||
size_t i;
|
||||
int c, debug = 0, daemonize = 0;
|
||||
char *pid_file = NULL;
|
||||
const char *log_file = NULL;
|
||||
|
||||
if (os_program_init())
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "Bdf:hKP:tv");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
if (wpa_debug_level > 0)
|
||||
wpa_debug_level--;
|
||||
break;
|
||||
case 'B':
|
||||
daemonize++;
|
||||
break;
|
||||
case 'f':
|
||||
log_file = optarg;
|
||||
break;
|
||||
case 'K':
|
||||
wpa_debug_show_keys++;
|
||||
break;
|
||||
case 'P':
|
||||
os_free(pid_file);
|
||||
pid_file = os_rel2abs_path(optarg);
|
||||
break;
|
||||
case 't':
|
||||
wpa_debug_timestamp++;
|
||||
break;
|
||||
case 'v':
|
||||
show_version();
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
usage();
|
||||
|
||||
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
|
||||
|
||||
if (log_file)
|
||||
wpa_debug_open_file(log_file);
|
||||
|
||||
interfaces.count = argc - optind;
|
||||
interfaces.iface = os_zalloc(interfaces.count *
|
||||
sizeof(struct hostapd_iface *));
|
||||
if (interfaces.iface == NULL) {
|
||||
wpa_printf(MSG_ERROR, "malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_global_init(&interfaces))
|
||||
return -1;
|
||||
|
||||
/* Initialize interfaces */
|
||||
for (i = 0; i < interfaces.count; i++) {
|
||||
interfaces.iface[i] = hostapd_interface_init(&interfaces,
|
||||
argv[optind + i],
|
||||
debug);
|
||||
if (!interfaces.iface[i])
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hostapd_global_run(&interfaces, daemonize, pid_file))
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
/* Deinitialize all interfaces */
|
||||
for (i = 0; i < interfaces.count; i++)
|
||||
hostapd_interface_deinit_free(interfaces.iface[i]);
|
||||
os_free(interfaces.iface);
|
||||
|
||||
hostapd_global_deinit(pid_file);
|
||||
os_free(pid_file);
|
||||
|
||||
if (log_file)
|
||||
wpa_debug_close_file();
|
||||
|
||||
os_program_deinit();
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,505 +0,0 @@
|
|||
/*
|
||||
* hostapd / RADIUS Accounting
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "ap_config.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "accounting.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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int accounting_sta_update_stats(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct hostap_sta_driver_data *data)
|
||||
{
|
||||
if (hostapd_drv_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_drv_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;
|
||||
struct os_time now;
|
||||
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;
|
||||
}
|
||||
|
||||
os_get_time(&now);
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
|
||||
now.sec - 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,
|
||||
now.sec)) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 (radius_msg_get_hdr(msg)->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);
|
||||
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)
|
||||
{
|
||||
struct os_time now;
|
||||
|
||||
/* Acct-Session-Id should be unique over reboots. If reliable clock is
|
||||
* not available, this could be replaced with reboot counter, etc. */
|
||||
os_get_time(&now);
|
||||
hapd->acct_session_id_hi = now.sec;
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,627 +0,0 @@
|
|||
/*
|
||||
* hostapd / Configuration helper functions
|
||||
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "eap_common/eap_wsc_common.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_config.h"
|
||||
|
||||
|
||||
static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
|
||||
{
|
||||
struct hostapd_vlan *vlan, *prev;
|
||||
|
||||
vlan = bss->vlan;
|
||||
prev = NULL;
|
||||
while (vlan) {
|
||||
prev = vlan;
|
||||
vlan = vlan->next;
|
||||
os_free(prev);
|
||||
}
|
||||
|
||||
bss->vlan = NULL;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
{
|
||||
bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
|
||||
bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
|
||||
bss->logger_syslog = (unsigned int) -1;
|
||||
bss->logger_stdout = (unsigned int) -1;
|
||||
|
||||
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
|
||||
|
||||
bss->wep_rekeying_period = 300;
|
||||
/* use key0 in individual key and key1 in broadcast key */
|
||||
bss->broadcast_key_idx_min = 1;
|
||||
bss->broadcast_key_idx_max = 2;
|
||||
bss->eap_reauth_period = 3600;
|
||||
|
||||
bss->wpa_group_rekey = 600;
|
||||
bss->wpa_gmk_rekey = 86400;
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
bss->wpa_pairwise = WPA_CIPHER_TKIP;
|
||||
bss->wpa_group = WPA_CIPHER_TKIP;
|
||||
bss->rsn_pairwise = 0;
|
||||
|
||||
bss->max_num_sta = MAX_STA_COUNT;
|
||||
|
||||
bss->dtim_period = 2;
|
||||
|
||||
bss->radius_server_auth_port = 1812;
|
||||
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
|
||||
bss->eapol_version = EAPOL_VERSION;
|
||||
|
||||
bss->max_listen_interval = 65535;
|
||||
|
||||
bss->pwd_group = 19; /* ECC: GF(p=256) */
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
bss->assoc_sa_query_max_timeout = 1000;
|
||||
bss->assoc_sa_query_retry_timeout = 201;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef EAP_SERVER_FAST
|
||||
/* both anonymous and authenticated provisioning */
|
||||
bss->eap_fast_prov = 3;
|
||||
bss->pac_key_lifetime = 7 * 24 * 60 * 60;
|
||||
bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
|
||||
#endif /* EAP_SERVER_FAST */
|
||||
|
||||
/* Set to -1 as defaults depends on HT in setup */
|
||||
bss->wmm_enabled = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
bss->ft_over_ds = 1;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_config * hostapd_config_defaults(void)
|
||||
{
|
||||
#define ecw2cw(ecw) ((1 << (ecw)) - 1)
|
||||
|
||||
struct hostapd_config *conf;
|
||||
struct hostapd_bss_config *bss;
|
||||
const int aCWmin = 4, aCWmax = 10;
|
||||
const struct hostapd_wmm_ac_params ac_bk =
|
||||
{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
|
||||
const struct hostapd_wmm_ac_params ac_be =
|
||||
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
|
||||
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
|
||||
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
|
||||
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
|
||||
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
|
||||
const struct hostapd_tx_queue_params txq_bk =
|
||||
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
|
||||
const struct hostapd_tx_queue_params txq_be =
|
||||
{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
|
||||
const struct hostapd_tx_queue_params txq_vi =
|
||||
{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
|
||||
const struct hostapd_tx_queue_params txq_vo =
|
||||
{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
|
||||
(ecw2cw(aCWmin) + 1) / 2 - 1, 15};
|
||||
|
||||
#undef ecw2cw
|
||||
|
||||
conf = os_zalloc(sizeof(*conf));
|
||||
bss = os_zalloc(sizeof(*bss));
|
||||
if (conf == NULL || bss == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||
"configuration data.");
|
||||
os_free(conf);
|
||||
os_free(bss);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bss->radius = os_zalloc(sizeof(*bss->radius));
|
||||
if (bss->radius == NULL) {
|
||||
os_free(conf);
|
||||
os_free(bss);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hostapd_config_defaults_bss(bss);
|
||||
|
||||
conf->num_bss = 1;
|
||||
conf->bss = bss;
|
||||
|
||||
conf->beacon_int = 100;
|
||||
conf->rts_threshold = -1; /* use driver default: 2347 */
|
||||
conf->fragm_threshold = -1; /* user driver default: 2346 */
|
||||
conf->send_probe_response = 1;
|
||||
|
||||
conf->wmm_ac_params[0] = ac_be;
|
||||
conf->wmm_ac_params[1] = ac_bk;
|
||||
conf->wmm_ac_params[2] = ac_vi;
|
||||
conf->wmm_ac_params[3] = ac_vo;
|
||||
|
||||
conf->tx_queue[0] = txq_vo;
|
||||
conf->tx_queue[1] = txq_vi;
|
||||
conf->tx_queue[2] = txq_be;
|
||||
conf->tx_queue[3] = txq_bk;
|
||||
|
||||
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b)
|
||||
{
|
||||
return os_memcmp(a, b, sizeof(macaddr));
|
||||
}
|
||||
|
||||
|
||||
int hostapd_mac_comp_empty(const void *a)
|
||||
{
|
||||
macaddr empty = { 0 };
|
||||
return os_memcmp(a, empty, sizeof(macaddr));
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
struct hostapd_ssid *ssid)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[128], *pos;
|
||||
int line = 0, ret = 0, len, ok;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct hostapd_wpa_psk *psk;
|
||||
|
||||
if (!fname)
|
||||
return 0;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (!f) {
|
||||
wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
line++;
|
||||
|
||||
if (buf[0] == '#')
|
||||
continue;
|
||||
pos = buf;
|
||||
while (*pos != '\0') {
|
||||
if (*pos == '\n') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (buf[0] == '\0')
|
||||
continue;
|
||||
|
||||
if (hwaddr_aton(buf, addr)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
|
||||
"line %d in '%s'", buf, line, fname);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
psk = os_zalloc(sizeof(*psk));
|
||||
if (psk == NULL) {
|
||||
wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (is_zero_ether_addr(addr))
|
||||
psk->group = 1;
|
||||
else
|
||||
os_memcpy(psk->addr, addr, ETH_ALEN);
|
||||
|
||||
pos = buf + 17;
|
||||
if (*pos == '\0') {
|
||||
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
|
||||
line, fname);
|
||||
os_free(psk);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
|
||||
ok = 0;
|
||||
len = os_strlen(pos);
|
||||
if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
|
||||
ok = 1;
|
||||
else if (len >= 8 && len < 64) {
|
||||
pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
|
||||
4096, psk->psk, PMK_LEN);
|
||||
ok = 1;
|
||||
}
|
||||
if (!ok) {
|
||||
wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
|
||||
"'%s'", pos, line, fname);
|
||||
os_free(psk);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
psk->next = ssid->wpa_psk;
|
||||
ssid->wpa_psk = psk;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_derive_psk(struct hostapd_ssid *ssid)
|
||||
{
|
||||
ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
|
||||
if (ssid->wpa_psk == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "SSID",
|
||||
(u8 *) ssid->ssid, ssid->ssid_len);
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
|
||||
(u8 *) ssid->wpa_passphrase,
|
||||
os_strlen(ssid->wpa_passphrase));
|
||||
pbkdf2_sha1(ssid->wpa_passphrase,
|
||||
ssid->ssid, ssid->ssid_len,
|
||||
4096, ssid->wpa_psk->psk, PMK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
|
||||
ssid->wpa_psk->psk, PMK_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct hostapd_ssid *ssid = &conf->ssid;
|
||||
|
||||
if (ssid->wpa_passphrase != NULL) {
|
||||
if (ssid->wpa_psk != NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
|
||||
"instead of passphrase");
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
|
||||
"passphrase");
|
||||
if (hostapd_derive_psk(ssid) < 0)
|
||||
return -1;
|
||||
}
|
||||
ssid->wpa_psk->group = 1;
|
||||
}
|
||||
|
||||
if (ssid->wpa_psk_file) {
|
||||
if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
|
||||
&conf->ssid))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a->idx != b->idx || a->default_len != b->default_len)
|
||||
return 1;
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++)
|
||||
if (a->len[i] != b->len[i] ||
|
||||
os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
|
||||
int num_servers)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
os_free(servers[i].shared_secret);
|
||||
}
|
||||
os_free(servers);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
|
||||
{
|
||||
os_free(user->identity);
|
||||
os_free(user->password);
|
||||
os_free(user);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
os_free(keys->key[i]);
|
||||
keys->key[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct hostapd_wpa_psk *psk, *prev;
|
||||
struct hostapd_eap_user *user, *prev_user;
|
||||
|
||||
if (conf == NULL)
|
||||
return;
|
||||
|
||||
psk = conf->ssid.wpa_psk;
|
||||
while (psk) {
|
||||
prev = psk;
|
||||
psk = psk->next;
|
||||
os_free(prev);
|
||||
}
|
||||
|
||||
os_free(conf->ssid.wpa_passphrase);
|
||||
os_free(conf->ssid.wpa_psk_file);
|
||||
hostapd_config_free_wep(&conf->ssid.wep);
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
os_free(conf->ssid.vlan_tagged_interface);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
user = conf->eap_user;
|
||||
while (user) {
|
||||
prev_user = user;
|
||||
user = user->next;
|
||||
hostapd_config_free_eap_user(prev_user);
|
||||
}
|
||||
|
||||
os_free(conf->dump_log_name);
|
||||
os_free(conf->eap_req_id_text);
|
||||
os_free(conf->accept_mac);
|
||||
os_free(conf->deny_mac);
|
||||
os_free(conf->nas_identifier);
|
||||
hostapd_config_free_radius(conf->radius->auth_servers,
|
||||
conf->radius->num_auth_servers);
|
||||
hostapd_config_free_radius(conf->radius->acct_servers,
|
||||
conf->radius->num_acct_servers);
|
||||
os_free(conf->rsn_preauth_interfaces);
|
||||
os_free(conf->ctrl_interface);
|
||||
os_free(conf->ca_cert);
|
||||
os_free(conf->server_cert);
|
||||
os_free(conf->private_key);
|
||||
os_free(conf->private_key_passwd);
|
||||
os_free(conf->dh_file);
|
||||
os_free(conf->pac_opaque_encr_key);
|
||||
os_free(conf->eap_fast_a_id);
|
||||
os_free(conf->eap_fast_a_id_info);
|
||||
os_free(conf->eap_sim_db);
|
||||
os_free(conf->radius_server_clients);
|
||||
os_free(conf->test_socket);
|
||||
os_free(conf->radius);
|
||||
hostapd_config_free_vlan(conf);
|
||||
if (conf->ssid.dyn_vlan_keys) {
|
||||
struct hostapd_ssid *ssid = &conf->ssid;
|
||||
size_t i;
|
||||
for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
|
||||
if (ssid->dyn_vlan_keys[i] == NULL)
|
||||
continue;
|
||||
hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
|
||||
os_free(ssid->dyn_vlan_keys[i]);
|
||||
}
|
||||
os_free(ssid->dyn_vlan_keys);
|
||||
ssid->dyn_vlan_keys = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
{
|
||||
struct ft_remote_r0kh *r0kh, *r0kh_prev;
|
||||
struct ft_remote_r1kh *r1kh, *r1kh_prev;
|
||||
|
||||
r0kh = conf->r0kh_list;
|
||||
conf->r0kh_list = NULL;
|
||||
while (r0kh) {
|
||||
r0kh_prev = r0kh;
|
||||
r0kh = r0kh->next;
|
||||
os_free(r0kh_prev);
|
||||
}
|
||||
|
||||
r1kh = conf->r1kh_list;
|
||||
conf->r1kh_list = NULL;
|
||||
while (r1kh) {
|
||||
r1kh_prev = r1kh;
|
||||
r1kh = r1kh->next;
|
||||
os_free(r1kh_prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
os_free(conf->wps_pin_requests);
|
||||
os_free(conf->device_name);
|
||||
os_free(conf->manufacturer);
|
||||
os_free(conf->model_name);
|
||||
os_free(conf->model_number);
|
||||
os_free(conf->serial_number);
|
||||
os_free(conf->config_methods);
|
||||
os_free(conf->ap_pin);
|
||||
os_free(conf->extra_cred);
|
||||
os_free(conf->ap_settings);
|
||||
os_free(conf->upnp_iface);
|
||||
os_free(conf->friendly_name);
|
||||
os_free(conf->manufacturer_url);
|
||||
os_free(conf->model_description);
|
||||
os_free(conf->model_url);
|
||||
os_free(conf->upc);
|
||||
#endif /* CONFIG_WPS */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_config_free - Free hostapd configuration
|
||||
* @conf: Configuration data from hostapd_config_read().
|
||||
*/
|
||||
void hostapd_config_free(struct hostapd_config *conf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (conf == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++)
|
||||
hostapd_config_free_bss(&conf->bss[i]);
|
||||
os_free(conf->bss);
|
||||
os_free(conf->supported_rates);
|
||||
os_free(conf->basic_rates);
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_maclist_found - Find a MAC address from a list
|
||||
* @list: MAC address list
|
||||
* @num_entries: Number of addresses in the list
|
||||
* @addr: Address to search for
|
||||
* @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
|
||||
* Returns: 1 if address is in the list or 0 if not.
|
||||
*
|
||||
* Perform a binary search for given MAC address from a pre-sorted list.
|
||||
*/
|
||||
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
|
||||
const u8 *addr, int *vlan_id)
|
||||
{
|
||||
int start, end, middle, res;
|
||||
|
||||
start = 0;
|
||||
end = num_entries - 1;
|
||||
|
||||
while (start <= end) {
|
||||
middle = (start + end) / 2;
|
||||
res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
|
||||
if (res == 0) {
|
||||
if (vlan_id)
|
||||
*vlan_id = list[middle].vlan_id;
|
||||
return 1;
|
||||
}
|
||||
if (res < 0)
|
||||
start = middle + 1;
|
||||
else
|
||||
end = middle - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_rate_found(int *list, int rate)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (list == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; list[i] >= 0; i++)
|
||||
if (list[i] == rate)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
|
||||
{
|
||||
struct hostapd_vlan *v = vlan;
|
||||
while (v) {
|
||||
if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
|
||||
return v->ifname;
|
||||
v = v->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
const u8 *addr, const u8 *prev_psk)
|
||||
{
|
||||
struct hostapd_wpa_psk *psk;
|
||||
int next_ok = prev_psk == NULL;
|
||||
|
||||
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
|
||||
if (next_ok &&
|
||||
(psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
|
||||
return psk->psk;
|
||||
|
||||
if (psk->psk == prev_psk)
|
||||
next_ok = 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const struct hostapd_eap_user *
|
||||
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
|
||||
size_t identity_len, int phase2)
|
||||
{
|
||||
struct hostapd_eap_user *user = conf->eap_user;
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
|
||||
os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
|
||||
static struct hostapd_eap_user wsc_enrollee;
|
||||
os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
|
||||
wsc_enrollee.methods[0].method = eap_server_get_type(
|
||||
"WSC", &wsc_enrollee.methods[0].vendor);
|
||||
return &wsc_enrollee;
|
||||
}
|
||||
|
||||
if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
|
||||
os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
|
||||
static struct hostapd_eap_user wsc_registrar;
|
||||
os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
|
||||
wsc_registrar.methods[0].method = eap_server_get_type(
|
||||
"WSC", &wsc_registrar.methods[0].vendor);
|
||||
wsc_registrar.password = (u8 *) conf->ap_pin;
|
||||
wsc_registrar.password_len = conf->ap_pin ?
|
||||
os_strlen(conf->ap_pin) : 0;
|
||||
return &wsc_registrar;
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
while (user) {
|
||||
if (!phase2 && user->identity == NULL) {
|
||||
/* Wildcard match */
|
||||
break;
|
||||
}
|
||||
|
||||
if (user->phase2 == !!phase2 && user->wildcard_prefix &&
|
||||
identity_len >= user->identity_len &&
|
||||
os_memcmp(user->identity, identity, user->identity_len) ==
|
||||
0) {
|
||||
/* Wildcard prefix match */
|
||||
break;
|
||||
}
|
||||
|
||||
if (user->phase2 == !!phase2 &&
|
||||
user->identity_len == identity_len &&
|
||||
os_memcmp(user->identity, identity, identity_len) == 0)
|
||||
break;
|
||||
user = user->next;
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
|
@ -1,417 +0,0 @@
|
|||
/*
|
||||
* hostapd / Configuration definitions and helpers functions
|
||||
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef HOSTAPD_CONFIG_H
|
||||
#define HOSTAPD_CONFIG_H
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "ip_addr.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "wps/wps.h"
|
||||
|
||||
#define MAX_STA_COUNT 2007
|
||||
#define MAX_VLAN_ID 4094
|
||||
|
||||
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 4
|
||||
|
||||
struct hostapd_tx_queue_params {
|
||||
int aifs;
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
|
||||
};
|
||||
|
||||
struct hostapd_wmm_ac_params {
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int aifs;
|
||||
int txop_limit; /* 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];
|
||||
char wds_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;
|
||||
int acct_interim_interval;
|
||||
|
||||
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 wds_sta;
|
||||
int isolate;
|
||||
|
||||
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 mfp_options 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;
|
||||
int ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
gid_t ctrl_interface_gid;
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
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;
|
||||
int fragment_size;
|
||||
u16 pwd_group;
|
||||
|
||||
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 wmm_enabled;
|
||||
int wmm_uapsd;
|
||||
|
||||
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;
|
||||
u8 device_type[WPS_DEV_TYPE_LEN];
|
||||
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;
|
||||
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#define P2P_ENABLED BIT(0)
|
||||
#define P2P_GROUP_OWNER BIT(1)
|
||||
#define P2P_GROUP_FORMATION BIT(2)
|
||||
#define P2P_MANAGE BIT(3)
|
||||
#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
|
||||
int p2p;
|
||||
|
||||
int disassoc_low_ack;
|
||||
|
||||
#define TDLS_PROHIBIT BIT(0)
|
||||
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
|
||||
int tdls;
|
||||
int disable_11n;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
enum 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 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];
|
||||
|
||||
/*
|
||||
* WMM 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_wmm_ac_params wmm_ac_params[4];
|
||||
|
||||
int ht_op_mode_fixed;
|
||||
u16 ht_capab;
|
||||
int ieee80211n;
|
||||
int secondary_channel;
|
||||
int require_ht;
|
||||
};
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b);
|
||||
int hostapd_mac_comp_empty(const void *a);
|
||||
struct hostapd_config * hostapd_config_defaults(void);
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
|
||||
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 /* HOSTAPD_CONFIG_H */
|
|
@ -1,632 +0,0 @@
|
|||
/*
|
||||
* hostapd - Driver operations
|
||||
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "wps/wps.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_config.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
|
||||
|
||||
u32 hostapd_sta_flags_to_drv(u32 flags)
|
||||
{
|
||||
int res = 0;
|
||||
if (flags & WLAN_STA_AUTHORIZED)
|
||||
res |= WPA_STA_AUTHORIZED;
|
||||
if (flags & WLAN_STA_WMM)
|
||||
res |= WPA_STA_WMM;
|
||||
if (flags & WLAN_STA_SHORT_PREAMBLE)
|
||||
res |= WPA_STA_SHORT_PREAMBLE;
|
||||
if (flags & WLAN_STA_MFP)
|
||||
res |= WPA_STA_MFP;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpabuf *beacon, *proberesp, *assocresp = NULL;
|
||||
int ret;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
|
||||
return 0;
|
||||
|
||||
beacon = hapd->wps_beacon_ie;
|
||||
proberesp = hapd->wps_probe_resp_ie;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
|
||||
beacon = NULL;
|
||||
else {
|
||||
beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
|
||||
wpabuf_len(hapd->wps_beacon_ie) : 0) +
|
||||
(hapd->p2p_beacon_ie ?
|
||||
wpabuf_len(hapd->p2p_beacon_ie) : 0));
|
||||
if (beacon == NULL)
|
||||
return -1;
|
||||
if (hapd->wps_beacon_ie)
|
||||
wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
|
||||
if (hapd->p2p_beacon_ie)
|
||||
wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
|
||||
}
|
||||
|
||||
if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
|
||||
proberesp = NULL;
|
||||
else {
|
||||
proberesp = wpabuf_alloc(
|
||||
(hapd->wps_probe_resp_ie ?
|
||||
wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
|
||||
(hapd->p2p_probe_resp_ie ?
|
||||
wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
|
||||
if (proberesp == NULL) {
|
||||
wpabuf_free(beacon);
|
||||
return -1;
|
||||
}
|
||||
if (hapd->wps_probe_resp_ie)
|
||||
wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
|
||||
if (hapd->p2p_probe_resp_ie)
|
||||
wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_P2P_MANAGER
|
||||
if (hapd->conf->p2p & P2P_MANAGE) {
|
||||
struct wpabuf *a;
|
||||
|
||||
a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
|
||||
if (a) {
|
||||
u8 *start, *p;
|
||||
if (beacon)
|
||||
wpabuf_put_buf(a, beacon);
|
||||
if (beacon != hapd->wps_beacon_ie)
|
||||
wpabuf_free(beacon);
|
||||
start = wpabuf_put(a, 0);
|
||||
p = hostapd_eid_p2p_manage(hapd, start);
|
||||
wpabuf_put(a, p - start);
|
||||
beacon = a;
|
||||
}
|
||||
|
||||
a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
|
||||
0));
|
||||
if (a) {
|
||||
u8 *start, *p;
|
||||
if (proberesp)
|
||||
wpabuf_put_buf(a, proberesp);
|
||||
if (proberesp != hapd->wps_probe_resp_ie)
|
||||
wpabuf_free(proberesp);
|
||||
start = wpabuf_put(a, 0);
|
||||
p = hostapd_eid_p2p_manage(hapd, start);
|
||||
wpabuf_put(a, p - start);
|
||||
proberesp = a;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
#ifdef CONFIG_WPS2
|
||||
if (hapd->conf->wps_state)
|
||||
assocresp = wps_build_assoc_resp_ie();
|
||||
#endif /* CONFIG_WPS2 */
|
||||
|
||||
#ifdef CONFIG_P2P_MANAGER
|
||||
if (hapd->conf->p2p & P2P_MANAGE) {
|
||||
struct wpabuf *a;
|
||||
a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
|
||||
0));
|
||||
if (a) {
|
||||
u8 *start, *p;
|
||||
start = wpabuf_put(a, 0);
|
||||
p = hostapd_eid_p2p_manage(hapd, start);
|
||||
wpabuf_put(a, p - start);
|
||||
if (assocresp) {
|
||||
wpabuf_put_buf(a, assocresp);
|
||||
wpabuf_free(assocresp);
|
||||
}
|
||||
assocresp = a;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
|
||||
assocresp);
|
||||
|
||||
if (beacon != hapd->wps_beacon_ie)
|
||||
wpabuf_free(beacon);
|
||||
if (proberesp != hapd->wps_probe_resp_ie)
|
||||
wpabuf_free(proberesp);
|
||||
wpabuf_free(assocresp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized)
|
||||
{
|
||||
if (authorized) {
|
||||
return hostapd_sta_set_flags(hapd, sta->addr,
|
||||
hostapd_sta_flags_to_drv(
|
||||
sta->flags),
|
||||
WPA_STA_AUTHORIZED, ~0);
|
||||
}
|
||||
|
||||
return hostapd_sta_set_flags(hapd, sta->addr,
|
||||
hostapd_sta_flags_to_drv(sta->flags),
|
||||
0, ~WPA_STA_AUTHORIZED);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int set_flags, total_flags, flags_and, flags_or;
|
||||
total_flags = hostapd_sta_flags_to_drv(sta->flags);
|
||||
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
|
||||
if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
|
||||
sta->auth_alg == WLAN_AUTH_FT) &&
|
||||
sta->flags & WLAN_STA_AUTHORIZED)
|
||||
set_flags |= WPA_STA_AUTHORIZED;
|
||||
flags_or = total_flags & set_flags;
|
||||
flags_and = total_flags | ~set_flags;
|
||||
return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
|
||||
flags_or, flags_and);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
|
||||
int enabled)
|
||||
{
|
||||
struct wpa_bss_params params;
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.ifname = ifname;
|
||||
params.enabled = enabled;
|
||||
if (enabled) {
|
||||
params.wpa = hapd->conf->wpa;
|
||||
params.ieee802_1x = hapd->conf->ieee802_1x;
|
||||
params.wpa_group = hapd->conf->wpa_group;
|
||||
params.wpa_pairwise = hapd->conf->wpa_pairwise;
|
||||
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
|
||||
params.rsn_preauth = hapd->conf->rsn_preauth;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
params.ieee80211w = hapd->conf->ieee80211w;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
}
|
||||
return hostapd_set_ieee8021x(hapd, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_intra_bss(hapd->drv_priv, !value);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection)
|
||||
{
|
||||
int ret = 0;
|
||||
int preamble;
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
u8 buf[60], *ht_capab, *ht_oper, *pos;
|
||||
|
||||
pos = buf;
|
||||
ht_capab = pos;
|
||||
pos = hostapd_eid_ht_capabilities(hapd, pos);
|
||||
ht_oper = pos;
|
||||
pos = hostapd_eid_ht_operation(hapd, pos);
|
||||
if (pos > ht_oper && ht_oper > ht_capab &&
|
||||
hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
|
||||
ht_oper + 2, ht_oper[1])) {
|
||||
wpa_printf(MSG_ERROR, "Could not set HT capabilities "
|
||||
"for kernel driver");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if (hostapd_set_cts_protect(hapd, use_protection)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
|
||||
"driver");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (hapd->iface->current_mode &&
|
||||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
|
||||
hostapd_set_short_slot_time(hapd,
|
||||
hapd->iface->num_sta_no_short_slot_time
|
||||
> 0 ? 0 : 1)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
|
||||
"in kernel driver");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (hapd->iface->num_sta_no_short_preamble == 0 &&
|
||||
hapd->iconf->preamble == SHORT_PREAMBLE)
|
||||
preamble = SHORT_PREAMBLE;
|
||||
else
|
||||
preamble = LONG_PREAMBLE;
|
||||
if (hostapd_set_preamble(hapd, preamble)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
|
||||
"driver");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) &&
|
||||
hapd->conf->isolate) {
|
||||
wpa_printf(MSG_ERROR, "Could not enable AP isolation in "
|
||||
"kernel driver");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
char force_ifname[IFNAMSIZ];
|
||||
u8 if_addr[ETH_ALEN];
|
||||
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
|
||||
NULL, NULL, force_ifname, if_addr, NULL);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
|
||||
int val)
|
||||
{
|
||||
const char *bridge = NULL;
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
|
||||
return 0;
|
||||
if (hapd->conf->wds_bridge[0])
|
||||
bridge = hapd->conf->wds_bridge;
|
||||
else if (hapd->conf->bridge[0])
|
||||
bridge = hapd->conf->bridge;
|
||||
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
|
||||
bridge);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const u8 *addr, u16 aid, u16 capability,
|
||||
const u8 *supp_rates, size_t supp_rates_len,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab)
|
||||
{
|
||||
struct hostapd_sta_add_params params;
|
||||
|
||||
if (hapd->driver == NULL)
|
||||
return 0;
|
||||
if (hapd->driver->sta_add == NULL)
|
||||
return 0;
|
||||
|
||||
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.listen_interval = listen_interval;
|
||||
params.ht_capabilities = ht_capab;
|
||||
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
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->drv_priv, enabled);
|
||||
}
|
||||
|
||||
|
||||
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->drv_priv, elem, elem_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
|
||||
return 0;
|
||||
return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
|
||||
return 0;
|
||||
return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname, const u8 *addr, void *bss_ctx,
|
||||
void **drv_priv, char *force_ifname, u8 *if_addr,
|
||||
const char *bridge)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
|
||||
return -1;
|
||||
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
|
||||
bss_ctx, drv_priv, force_ifname, if_addr,
|
||||
bridge);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
|
||||
return -1;
|
||||
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
||||
struct wpa_bss_params *params)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->flush == NULL)
|
||||
return 0;
|
||||
return hapd->driver->flush(hapd->drv_priv);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
|
||||
int channel, int ht_enabled, int sec_channel_offset)
|
||||
{
|
||||
struct hostapd_freq_params data;
|
||||
if (hapd->driver == NULL)
|
||||
return 0;
|
||||
if (hapd->driver->set_freq == NULL)
|
||||
return 0;
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
data.mode = mode;
|
||||
data.freq = freq;
|
||||
data.channel = channel;
|
||||
data.ht_enabled = ht_enabled;
|
||||
data.sec_channel_offset = sec_channel_offset;
|
||||
return hapd->driver->set_freq(hapd->drv_priv, &data);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
|
||||
int *basic_rates, int mode)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
|
||||
basic_rates, mode);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_country == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_country(hapd->drv_priv, country);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_cts_protect(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_preamble(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_preamble(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *mask)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
|
||||
return 1;
|
||||
return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_set_ht_params(struct hostapd_data *hapd,
|
||||
const u8 *ht_capab, size_t ht_capab_len,
|
||||
const u8 *ht_oper, size_t ht_oper_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
|
||||
ht_capab == NULL || ht_oper == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_ht_params(hapd->drv_priv,
|
||||
ht_capab, ht_capab_len,
|
||||
ht_oper, ht_oper_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_none(struct hostapd_data *hapd)
|
||||
{
|
||||
return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
struct wpa_driver_scan_params *params)
|
||||
{
|
||||
if (hapd->driver && hapd->driver->scan2)
|
||||
return hapd->driver->scan2(hapd->drv_priv, params);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct wpa_scan_results * hostapd_driver_get_scan_results(
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver && hapd->driver->get_scan_results2)
|
||||
return hapd->driver->get_scan_results2(hapd->drv_priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
|
||||
int duration)
|
||||
{
|
||||
if (hapd->driver && hapd->driver->set_noa)
|
||||
return hapd->driver->set_noa(hapd->drv_priv, count, start,
|
||||
duration);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
|
||||
enum wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
|
||||
key_idx, set_tx, seq, seq_len, key,
|
||||
key_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
|
||||
reason);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
|
||||
reason);
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* hostapd - Driver operations
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef AP_DRV_OPS
|
||||
#define AP_DRV_OPS
|
||||
|
||||
enum wpa_driver_if_type;
|
||||
struct wpa_bss_params;
|
||||
struct wpa_driver_scan_params;
|
||||
struct ieee80211_ht_capabilities;
|
||||
|
||||
u32 hostapd_sta_flags_to_drv(u32 flags);
|
||||
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
|
||||
int hostapd_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
|
||||
int enabled);
|
||||
int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection);
|
||||
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
|
||||
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
|
||||
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
|
||||
int val);
|
||||
int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const u8 *addr, u16 aid, u16 capability,
|
||||
const u8 *supp_rates, size_t supp_rates_len,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||
size_t elem_len);
|
||||
int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
|
||||
int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
|
||||
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname, const u8 *addr, void *bss_ctx,
|
||||
void **drv_priv, char *force_ifname, u8 *if_addr,
|
||||
const char *bridge);
|
||||
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
const char *ifname);
|
||||
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
|
||||
struct wpa_bss_params *params);
|
||||
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||
const u8 *addr, int idx, u8 *seq);
|
||||
int hostapd_flush(struct hostapd_data *hapd);
|
||||
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
|
||||
int channel, int ht_enabled, int sec_channel_offset);
|
||||
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
|
||||
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
|
||||
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||
int total_flags, int flags_or, int flags_and);
|
||||
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
|
||||
int *basic_rates, int mode);
|
||||
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
|
||||
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
|
||||
int hostapd_set_preamble(struct hostapd_data *hapd, int value);
|
||||
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
|
||||
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time);
|
||||
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *mask);
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags);
|
||||
int hostapd_driver_commit(struct hostapd_data *hapd);
|
||||
int hostapd_set_ht_params(struct hostapd_data *hapd,
|
||||
const u8 *ht_capab, size_t ht_capab_len,
|
||||
const u8 *ht_oper, size_t ht_oper_len);
|
||||
int hostapd_drv_none(struct hostapd_data *hapd);
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
struct wpa_driver_scan_params *params);
|
||||
struct wpa_scan_results * hostapd_driver_get_scan_results(
|
||||
struct hostapd_data *hapd);
|
||||
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
|
||||
int duration);
|
||||
int hostapd_drv_set_key(const char *ifname,
|
||||
struct hostapd_data *hapd,
|
||||
enum wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len);
|
||||
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len);
|
||||
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason);
|
||||
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason);
|
||||
|
||||
|
||||
#include "drivers/driver.h"
|
||||
|
||||
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
|
||||
int enabled)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->hapd_set_countermeasures == NULL)
|
||||
return 0;
|
||||
return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_set_sta_vlan(const char *ifname,
|
||||
struct hostapd_data *hapd,
|
||||
const u8 *addr, int vlan_id)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
|
||||
vlan_id);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
|
||||
return 0;
|
||||
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_remove(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *data,
|
||||
size_t data_len, int encrypt,
|
||||
u32 flags)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
|
||||
return 0;
|
||||
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
|
||||
data_len, encrypt,
|
||||
hapd->own_addr, flags);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_read_sta_data(
|
||||
struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
|
||||
return -1;
|
||||
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd,
|
||||
const u8 *head, size_t head_len,
|
||||
const u8 *tail, size_t tail_len,
|
||||
int dtim_period, int beacon_int)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_beacon(hapd->drv_priv,
|
||||
head, head_len, tail, tail_len,
|
||||
dtim_period, beacon_int);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
|
||||
const u8 *mac, int accepted,
|
||||
u32 session_timeout)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
|
||||
session_timeout);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
|
||||
const u8 *mac)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->set_radius_acl_expire == NULL)
|
||||
return 0;
|
||||
return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
|
||||
}
|
||||
|
||||
#endif /* AP_DRV_OPS */
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Authentication server setup
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef AUTHSRV_H
|
||||
#define AUTHSRV_H
|
||||
|
||||
int authsrv_init(struct hostapd_data *hapd);
|
||||
void authsrv_deinit(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* AUTHSRV_H */
|
|
@ -1,540 +0,0 @@
|
|||
/*
|
||||
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
|
||||
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "utils/includes.h"
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "wps/wps_defs.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wmm.h"
|
||||
#include "ap_config.h"
|
||||
#include "sta_info.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "beacon.h"
|
||||
|
||||
|
||||
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 ||
|
||||
hapd->iconf->preamble == LONG_PREAMBLE)
|
||||
erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
|
||||
|
||||
return erp;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
*eid++ = WLAN_EID_DS_PARAMS;
|
||||
*eid++ = 1;
|
||||
*eid++ = hapd->iconf->channel;
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
if (hapd->iface->current_mode == NULL ||
|
||||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||
return eid;
|
||||
|
||||
/* Set NonERP_present and use_protection bits if there
|
||||
* are any associated NonERP stations. */
|
||||
/* TODO: use_protection bit can be set to zero even if
|
||||
* there are NonERP stations present. This optimization
|
||||
* might be useful if NonERP stations are "quiet".
|
||||
* See 802.11g/D6 E-1 for recommended practice.
|
||||
* In addition, Non ERP present might be set, if AP detects Non ERP
|
||||
* operation on other APs. */
|
||||
|
||||
/* Add ERP Information element */
|
||||
*eid++ = WLAN_EID_ERP_INFO;
|
||||
*eid++ = 1;
|
||||
*eid++ = ieee802_11_erp_info(hapd);
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_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,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_mgmt *resp;
|
||||
struct ieee802_11_elems elems;
|
||||
char *ssid;
|
||||
u8 *pos, *epos;
|
||||
const u8 *ie;
|
||||
size_t ssid_len, ie_len;
|
||||
struct sta_info *sta = NULL;
|
||||
size_t buflen;
|
||||
size_t i;
|
||||
|
||||
ie = mgmt->u.probe_req.variable;
|
||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
|
||||
return;
|
||||
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
|
||||
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
|
||||
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
|
||||
mgmt->sa, ie, ie_len) > 0)
|
||||
return;
|
||||
|
||||
if (!hapd->iconf->send_probe_response)
|
||||
return;
|
||||
|
||||
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
|
||||
wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
|
||||
MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
ssid = NULL;
|
||||
ssid_len = 0;
|
||||
|
||||
if ((!elems.ssid || !elems.supp_rates)) {
|
||||
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
|
||||
"without SSID or supported rates element",
|
||||
MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p && elems.wps_ie) {
|
||||
struct wpabuf *wps;
|
||||
wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
|
||||
if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
|
||||
wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
|
||||
"due to mismatch with Requested Device "
|
||||
"Type");
|
||||
wpabuf_free(wps);
|
||||
return;
|
||||
}
|
||||
wpabuf_free(wps);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
|
||||
elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
|
||||
os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
|
||||
P2P_WILDCARD_SSID_LEN) == 0) {
|
||||
/* Process P2P Wildcard SSID like Wildcard SSID */
|
||||
elems.ssid_len = 0;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
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' (DA " MACSTR ")",
|
||||
MAC2STR(mgmt->sa), ssid_txt,
|
||||
MAC2STR(mgmt->da));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: verify that supp_rates contains at least one matching rate
|
||||
* with AP configuration */
|
||||
#define MAX_PROBERESP_LEN 768
|
||||
buflen = MAX_PROBERESP_LEN;
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->wps_probe_resp_ie)
|
||||
buflen += wpabuf_len(hapd->wps_probe_resp_ie);
|
||||
#endif /* CONFIG_WPS */
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p_probe_resp_ie)
|
||||
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
|
||||
#endif /* CONFIG_P2P */
|
||||
resp = os_zalloc(buflen);
|
||||
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);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
pos = hostapd_eid_ht_capabilities(hapd, pos);
|
||||
pos = hostapd_eid_ht_operation(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
pos = hostapd_eid_ext_capab(hapd, pos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
pos = hostapd_eid_wmm(hapd, pos);
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
|
||||
wpabuf_len(hapd->wps_probe_resp_ie));
|
||||
pos += wpabuf_len(hapd->wps_probe_resp_ie);
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p &&
|
||||
hapd->p2p_probe_resp_ie) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
|
||||
wpabuf_len(hapd->p2p_probe_resp_ie));
|
||||
pos += wpabuf_len(hapd->p2p_probe_resp_ie);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_P2P_MANAGER
|
||||
if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
|
||||
P2P_MANAGE)
|
||||
pos = hostapd_eid_p2p_manage(hapd, pos);
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
|
||||
perror("handle_probe_req: send");
|
||||
|
||||
os_free(resp);
|
||||
|
||||
wpa_printf(MSG_EXCESSIVE, "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;
|
||||
u16 capab_info;
|
||||
size_t head_len, tail_len;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
|
||||
goto no_beacon;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#define BEACON_HEAD_BUF_SIZE 256
|
||||
#define BEACON_TAIL_BUF_SIZE 512
|
||||
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
|
||||
tail_len = BEACON_TAIL_BUF_SIZE;
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state && hapd->wps_beacon_ie)
|
||||
tail_len += wpabuf_len(hapd->wps_beacon_ie);
|
||||
#endif /* CONFIG_WPS */
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p_beacon_ie)
|
||||
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
|
||||
#endif /* CONFIG_P2P */
|
||||
tailpos = tail = os_malloc(tail_len);
|
||||
if (head == NULL || tail == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set beacon data");
|
||||
os_free(head);
|
||||
os_free(tail);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos, NULL);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
|
||||
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
|
||||
|
||||
//DRIVER_RTW ADD
|
||||
if(hapd->iconf->ieee80211n)
|
||||
hapd->conf->wmm_enabled = 1;
|
||||
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
tailpos = hostapd_eid_wmm(hapd, tailpos);
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
|
||||
wpabuf_len(hapd->wps_beacon_ie));
|
||||
tailpos += wpabuf_len(hapd->wps_beacon_ie);
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
|
||||
wpabuf_len(hapd->p2p_beacon_ie));
|
||||
tailpos += wpabuf_len(hapd->p2p_beacon_ie);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_P2P_MANAGER
|
||||
if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
|
||||
P2P_MANAGE)
|
||||
tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
tail_len = tailpos > tail ? tailpos - tail : 0;
|
||||
|
||||
if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len,
|
||||
tail, tail_len, hapd->conf->dtim_period,
|
||||
hapd->iconf->beacon_int))
|
||||
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
|
||||
"period");
|
||||
|
||||
os_free(tail);
|
||||
os_free(head);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
no_beacon:
|
||||
#endif /* CONFIG_P2P */
|
||||
hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
|
||||
ERP_INFO_USE_PROTECTION));
|
||||
}
|
||||
|
||||
|
||||
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 */
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
struct ieee80211_mgmt;
|
||||
|
||||
void handle_probe_req(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len);
|
||||
#ifdef NEED_AP_MLME
|
||||
void ieee802_11_set_beacon(struct hostapd_data *hapd);
|
||||
void ieee802_11_set_beacons(struct hostapd_iface *iface);
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#endif /* BEACON_H */
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Control interface for shared AP commands
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "sta_info.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ctrl_iface_ap.h"
|
||||
|
||||
|
||||
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;
|
||||
res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
|
||||
buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Control interface for shared AP commands
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef CTRL_IFACE_AP_H
|
||||
#define CTRL_IFACE_AP_H
|
||||
|
||||
int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
|
||||
char *buf, size_t buflen);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
|
@ -1,539 +0,0 @@
|
|||
/*
|
||||
* hostapd / Callback functions for driver wrappers
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "radius/radius.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "crypto/random.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "wps/wps.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "sta_info.h"
|
||||
#include "accounting.h"
|
||||
#include "tkip_countermeasures.h"
|
||||
#include "iapp.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wmm.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
|
||||
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *ie, size_t ielen, int reassoc)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int new_assoc, res;
|
||||
struct ieee802_11_elems elems;
|
||||
#ifdef CONFIG_P2P
|
||||
const u8 *all_ies = ie;
|
||||
size_t all_ies_len = ielen;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (addr == NULL) {
|
||||
/*
|
||||
* This could potentially happen with unexpected event from the
|
||||
* driver wrapper. This was seen at least in one case where the
|
||||
* driver ended up being set to station mode while hostapd was
|
||||
* running, so better make sure we stop processing such an
|
||||
* event here.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
|
||||
"no address");
|
||||
return -1;
|
||||
}
|
||||
random_add_randomness(addr, ETH_ALEN);
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "associated");
|
||||
|
||||
ieee802_11_parse_elems(ie, ielen, &elems, 0);
|
||||
if (elems.wps_ie) {
|
||||
ie = elems.wps_ie - 2;
|
||||
ielen = elems.wps_ie_len + 2;
|
||||
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
|
||||
} else if (elems.rsn_ie) {
|
||||
ie = elems.rsn_ie - 2;
|
||||
ielen = elems.rsn_ie_len + 2;
|
||||
wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
|
||||
} else if (elems.wpa_ie) {
|
||||
ie = elems.wpa_ie - 2;
|
||||
ielen = elems.wpa_ie_len + 2;
|
||||
wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
|
||||
} else {
|
||||
ie = NULL;
|
||||
ielen = 0;
|
||||
wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
|
||||
"(Re)AssocReq");
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta) {
|
||||
accounting_sta_stop(hapd, sta);
|
||||
} else {
|
||||
sta = ap_sta_add(hapd, addr);
|
||||
if (sta == NULL)
|
||||
return -1;
|
||||
}
|
||||
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (elems.p2p) {
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len,
|
||||
P2P_IE_VENDOR_TYPE);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (hapd->conf->wpa) {
|
||||
if (ie == NULL || ielen == 0) {
|
||||
if (hapd->conf->wps_state) {
|
||||
wpa_printf(MSG_DEBUG, "STA did not include "
|
||||
"WPA/RSN IE in (Re)Association "
|
||||
"Request - possible WPS use");
|
||||
sta->flags |= WLAN_STA_MAYBE_WPS;
|
||||
goto skip_wpa_check;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
|
||||
return -1;
|
||||
}
|
||||
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
|
||||
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
goto skip_wpa_check;
|
||||
}
|
||||
|
||||
if (sta->wpa_sm == NULL)
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
|
||||
sta->addr);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
|
||||
"machine");
|
||||
return -1;
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
ie, ielen, NULL, 0);
|
||||
if (res != WPA_IE_OK) {
|
||||
int resp;
|
||||
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
|
||||
"rejected? (res %u)", res);
|
||||
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
|
||||
if (res == WPA_INVALID_GROUP)
|
||||
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_PAIRWISE)
|
||||
resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
|
||||
else if (res == WPA_INVALID_AKMP)
|
||||
resp = WLAN_REASON_AKMP_NOT_VALID;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
|
||||
resp = WLAN_REASON_INVALID_IE;
|
||||
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
|
||||
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else
|
||||
resp = WLAN_REASON_INVALID_IE;
|
||||
hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
|
||||
ap_free_sta(hapd, sta);
|
||||
return -1;
|
||||
}
|
||||
} else if (hapd->conf->wps_state) {
|
||||
#ifdef CONFIG_WPS_STRICT
|
||||
if (ie) {
|
||||
struct wpabuf *wps;
|
||||
wps = ieee802_11_vendor_ie_concat(ie, ielen,
|
||||
WPS_IE_VENDOR_TYPE);
|
||||
if (wps && wps_validate_assoc_req(wps) < 0) {
|
||||
hostapd_drv_sta_disassoc(
|
||||
hapd, sta->addr,
|
||||
WLAN_REASON_INVALID_IE);
|
||||
ap_free_sta(hapd, sta);
|
||||
wpabuf_free(wps);
|
||||
return -1;
|
||||
}
|
||||
wpabuf_free(wps);
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
|
||||
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
} else
|
||||
sta->flags |= WLAN_STA_MAYBE_WPS;
|
||||
}
|
||||
skip_wpa_check:
|
||||
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
|
||||
all_ies, all_ies_len);
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
if (addr == NULL) {
|
||||
/*
|
||||
* This could potentially happen with unexpected event from the
|
||||
* driver wrapper. This was seen at least in one case where the
|
||||
* driver ended up reporting a station mode event while hostapd
|
||||
* was running, so better make sure we stop processing such an
|
||||
* event here.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
|
||||
"with no address");
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disassociated");
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "Disassociation notification for "
|
||||
"unknown STA " MACSTR, MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
|
||||
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
ap_free_sta(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (!sta || !hapd->conf->disassoc_low_ack)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
|
||||
"missing ACKs");
|
||||
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
if (sta)
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
size_t i;
|
||||
int ret = 0;
|
||||
|
||||
if (sa == NULL || ie == NULL)
|
||||
return -1;
|
||||
|
||||
random_add_randomness(sa, ETH_ALEN);
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
|
||||
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
|
||||
sa, ie, ie_len) > 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HOSTAPD
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
|
||||
static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
|
||||
{
|
||||
u16 fc, type, stype;
|
||||
|
||||
/*
|
||||
* PS-Poll frames are 16 bytes. All other frames are
|
||||
* 24 bytes or longer.
|
||||
*/
|
||||
if (len < 16)
|
||||
return NULL;
|
||||
|
||||
fc = le_to_host16(hdr->frame_control);
|
||||
type = WLAN_FC_GET_TYPE(fc);
|
||||
stype = WLAN_FC_GET_STYPE(fc);
|
||||
|
||||
switch (type) {
|
||||
case WLAN_FC_TYPE_DATA:
|
||||
if (len < 24)
|
||||
return NULL;
|
||||
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
|
||||
case WLAN_FC_FROMDS | WLAN_FC_TODS:
|
||||
case WLAN_FC_TODS:
|
||||
return hdr->addr1;
|
||||
case WLAN_FC_FROMDS:
|
||||
return hdr->addr2;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
case WLAN_FC_TYPE_CTRL:
|
||||
if (stype != WLAN_FC_STYPE_PSPOLL)
|
||||
return NULL;
|
||||
return hdr->addr1;
|
||||
case WLAN_FC_TYPE_MGMT:
|
||||
return hdr->addr3;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
|
||||
|
||||
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
|
||||
const u8 *bssid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (bssid == NULL)
|
||||
return NULL;
|
||||
if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
|
||||
bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
|
||||
return HAPD_BROADCAST;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
|
||||
return iface->bss[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
|
||||
const u8 *frame, size_t len)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
|
||||
u16 fc = le_to_host16(hdr->frame_control);
|
||||
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
|
||||
if (hapd == NULL || hapd == HAPD_BROADCAST)
|
||||
return;
|
||||
|
||||
ieee802_11_rx_from_unknown(hapd, hdr->addr2,
|
||||
(fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
|
||||
(WLAN_FC_TODS | WLAN_FC_FROMDS));
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
const struct ieee80211_hdr *hdr;
|
||||
const u8 *bssid;
|
||||
struct hostapd_frame_info fi;
|
||||
|
||||
hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
|
||||
bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
|
||||
if (bssid == NULL)
|
||||
return;
|
||||
|
||||
hapd = get_hapd_bssid(iface, bssid);
|
||||
if (hapd == NULL) {
|
||||
u16 fc;
|
||||
fc = le_to_host16(hdr->frame_control);
|
||||
|
||||
/*
|
||||
* Drop frames to unknown BSSIDs except for Beacon frames which
|
||||
* could be used to update neighbor information.
|
||||
*/
|
||||
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
|
||||
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
|
||||
hapd = iface->bss[0];
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
os_memset(&fi, 0, sizeof(fi));
|
||||
fi.datarate = rx_mgmt->datarate;
|
||||
fi.ssi_signal = rx_mgmt->ssi_signal;
|
||||
|
||||
if (hapd == HAPD_BROADCAST) {
|
||||
size_t i;
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
|
||||
rx_mgmt->frame_len, &fi);
|
||||
} else
|
||||
ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
|
||||
|
||||
random_add_randomness(&fi, sizeof(fi));
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
|
||||
size_t len, u16 stype, int ok)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
hdr = (struct ieee80211_hdr *) buf;
|
||||
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
|
||||
if (hapd == NULL || hapd == HAPD_BROADCAST)
|
||||
return;
|
||||
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
return 0;
|
||||
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
if (ap_get_sta(iface->bss[j], src)) {
|
||||
hapd = iface->bss[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ieee802_1x_receive(hapd, src, data, data_len);
|
||||
}
|
||||
|
||||
|
||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
switch (event) {
|
||||
case EVENT_MICHAEL_MIC_FAILURE:
|
||||
michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
|
||||
break;
|
||||
case EVENT_SCAN_RESULTS:
|
||||
if (hapd->iface->scan_cb)
|
||||
hapd->iface->scan_cb(hapd->iface);
|
||||
break;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
case EVENT_FT_RRB_RX:
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
|
||||
data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
|
||||
break;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
case EVENT_WPS_BUTTON_PUSHED:
|
||||
hostapd_wps_button_pushed(hapd, NULL);
|
||||
break;
|
||||
#ifdef NEED_AP_MLME
|
||||
case EVENT_TX_STATUS:
|
||||
switch (data->tx_status.type) {
|
||||
case WLAN_FC_TYPE_MGMT:
|
||||
hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
|
||||
data->tx_status.data_len,
|
||||
data->tx_status.stype,
|
||||
data->tx_status.ack);
|
||||
break;
|
||||
case WLAN_FC_TYPE_DATA:
|
||||
hostapd_tx_status(hapd, data->tx_status.dst,
|
||||
data->tx_status.data,
|
||||
data->tx_status.data_len,
|
||||
data->tx_status.ack);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EVENT_RX_FROM_UNKNOWN:
|
||||
hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
|
||||
data->rx_from_unknown.len);
|
||||
break;
|
||||
case EVENT_RX_MGMT:
|
||||
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
|
||||
break;
|
||||
#endif /* NEED_AP_MLME */
|
||||
case EVENT_RX_PROBE_REQ:
|
||||
if (data->rx_probe_req.sa == NULL ||
|
||||
data->rx_probe_req.ie == NULL)
|
||||
break;
|
||||
hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
|
||||
data->rx_probe_req.ie,
|
||||
data->rx_probe_req.ie_len);
|
||||
break;
|
||||
case EVENT_NEW_STA:
|
||||
hostapd_event_new_sta(hapd, data->new_sta.addr);
|
||||
break;
|
||||
case EVENT_EAPOL_RX:
|
||||
hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
|
||||
data->eapol_rx.data,
|
||||
data->eapol_rx.data_len);
|
||||
break;
|
||||
case EVENT_ASSOC:
|
||||
hostapd_notif_assoc(hapd, data->assoc_info.addr,
|
||||
data->assoc_info.req_ies,
|
||||
data->assoc_info.req_ies_len,
|
||||
data->assoc_info.reassoc);
|
||||
break;
|
||||
case EVENT_DISASSOC:
|
||||
if (data)
|
||||
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
|
||||
break;
|
||||
case EVENT_DEAUTH:
|
||||
if (data)
|
||||
hostapd_notif_disassoc(hapd, data->deauth_info.addr);
|
||||
break;
|
||||
case EVENT_STATION_LOW_ACK:
|
||||
if (!data)
|
||||
break;
|
||||
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HOSTAPD */
|
|
@ -1,929 +0,0 @@
|
|||
/*
|
||||
* hostapd / Initialization and configuration
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "hostapd.h"
|
||||
#include "authsrv.h"
|
||||
#include "sta_info.h"
|
||||
#include "accounting.h"
|
||||
#include "ap_list.h"
|
||||
#include "beacon.h"
|
||||
#include "iapp.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
#include "vlan_init.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "hw_features.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "p2p_hostapd.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd);
|
||||
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
|
||||
|
||||
extern int wpa_debug_level;
|
||||
|
||||
|
||||
static void hostapd_reload_bss(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_client_reconfig(hapd->radius, hapd->conf->radius);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
if (hostapd_setup_wpa_psk(hapd->conf)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
|
||||
"after reloading configuration");
|
||||
}
|
||||
|
||||
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
|
||||
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
|
||||
else
|
||||
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
|
||||
|
||||
if (hapd->conf->wpa && hapd->wpa_auth == NULL)
|
||||
hostapd_setup_wpa(hapd);
|
||||
else if (hapd->conf->wpa) {
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
hostapd_reconfig_wpa(hapd);
|
||||
wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
|
||||
if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
|
||||
wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
|
||||
"the kernel driver.");
|
||||
} else if (hapd->wpa_auth) {
|
||||
wpa_deinit(hapd->wpa_auth);
|
||||
hapd->wpa_auth = NULL;
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
hostapd_setup_encryption(hapd->conf->iface, hapd);
|
||||
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
|
||||
}
|
||||
|
||||
ieee802_11_set_beacon(hapd);
|
||||
hostapd_update_wps(hapd);
|
||||
|
||||
if (hapd->conf->ssid.ssid_set &&
|
||||
hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
|
||||
/* try to continue */
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_config *newconf, *oldconf;
|
||||
size_t j;
|
||||
|
||||
if (iface->config_read_cb == NULL)
|
||||
return -1;
|
||||
newconf = iface->config_read_cb(iface->config_fname);
|
||||
if (newconf == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Deauthenticate all stations since the new configuration may not
|
||||
* allow them to use the BSS anymore.
|
||||
*/
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hostapd_flush_old_stations(iface->bss[j]);
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
/* TODO: update dynamic data based on changed configuration
|
||||
* items (e.g., open/close sockets, etc.) */
|
||||
radius_client_flush(iface->bss[j]->radius, 0);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
}
|
||||
|
||||
oldconf = hapd->iconf;
|
||||
iface->conf = newconf;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
hapd->iconf = newconf;
|
||||
hapd->conf = &newconf->bss[j];
|
||||
hostapd_reload_bss(hapd);
|
||||
}
|
||||
|
||||
hostapd_config_free(oldconf);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
|
||||
char *ifname)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
|
||||
0, NULL, 0, NULL, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to clear default "
|
||||
"encryption keys (ifname=%s keyidx=%d)",
|
||||
ifname, i);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (hapd->conf->ieee80211w) {
|
||||
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
|
||||
NULL, i, 0, NULL,
|
||||
0, NULL, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to clear "
|
||||
"default mgmt encryption keys "
|
||||
"(ifname=%s keyidx=%d)", ifname, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
|
||||
{
|
||||
hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
|
||||
{
|
||||
int errors = 0, idx;
|
||||
struct hostapd_ssid *ssid = &hapd->conf->ssid;
|
||||
|
||||
idx = ssid->wep.idx;
|
||||
if (ssid->wep.default_len &&
|
||||
hostapd_drv_set_key(hapd->conf->iface,
|
||||
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
|
||||
1, NULL, 0, ssid->wep.key[idx],
|
||||
ssid->wep.len[idx])) {
|
||||
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
|
||||
errors++;
|
||||
}
|
||||
|
||||
if (ssid->dyn_vlan_keys) {
|
||||
size_t i;
|
||||
for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
|
||||
const char *ifname;
|
||||
struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
|
||||
if (key == NULL)
|
||||
continue;
|
||||
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
|
||||
i);
|
||||
if (ifname == NULL)
|
||||
continue;
|
||||
|
||||
idx = key->idx;
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
|
||||
broadcast_ether_addr, idx, 1,
|
||||
NULL, 0, key->key[idx],
|
||||
key->len[idx])) {
|
||||
wpa_printf(MSG_WARNING, "Could not set "
|
||||
"dynamic VLAN WEP encryption.");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* hostapd_cleanup - Per-BSS cleanup (deinitialization)
|
||||
* @hapd: Pointer to BSS data
|
||||
*
|
||||
* This function is used to free all per-BSS data structures and resources.
|
||||
* This gets called in a loop for each BSS between calls to
|
||||
* hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
|
||||
* is deinitialized. Most of the modules that are initialized in
|
||||
* hostapd_setup_bss() are deinitialized here.
|
||||
*/
|
||||
static void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->iface->ctrl_iface_deinit)
|
||||
hapd->iface->ctrl_iface_deinit(hapd);
|
||||
|
||||
iapp_deinit(hapd->iapp);
|
||||
hapd->iapp = NULL;
|
||||
accounting_deinit(hapd);
|
||||
hostapd_deinit_wpa(hapd);
|
||||
vlan_deinit(hapd);
|
||||
hostapd_acl_deinit(hapd);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_client_deinit(hapd->radius);
|
||||
hapd->radius = NULL;
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
hostapd_deinit_wps(hapd);
|
||||
|
||||
authsrv_deinit(hapd);
|
||||
|
||||
if (hapd->interface_added &&
|
||||
hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
|
||||
wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
|
||||
hapd->conf->iface);
|
||||
}
|
||||
|
||||
os_free(hapd->probereq_cb);
|
||||
hapd->probereq_cb = NULL;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
wpabuf_free(hapd->p2p_beacon_ie);
|
||||
hapd->p2p_beacon_ie = NULL;
|
||||
wpabuf_free(hapd->p2p_probe_resp_ie);
|
||||
hapd->p2p_probe_resp_ie = NULL;
|
||||
#endif /* CONFIG_P2P */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
|
||||
* @iface: Pointer to interface data
|
||||
*
|
||||
* This function is called before per-BSS data structures are deinitialized
|
||||
* with hostapd_cleanup().
|
||||
*/
|
||||
static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_cleanup_iface - Complete per-interface cleanup
|
||||
* @iface: Pointer to interface data
|
||||
*
|
||||
* This function is called after per-BSS data structures are deinitialized
|
||||
* with hostapd_cleanup().
|
||||
*/
|
||||
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
||||
{
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = NULL;
|
||||
os_free(iface->current_rates);
|
||||
iface->current_rates = NULL;
|
||||
ap_list_deinit(iface);
|
||||
hostapd_config_free(iface->conf);
|
||||
iface->conf = NULL;
|
||||
|
||||
os_free(iface->config_fname);
|
||||
os_free(iface->bss);
|
||||
os_free(iface);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
|
||||
{
|
||||
int i;
|
||||
|
||||
hostapd_broadcast_wep_set(hapd);
|
||||
|
||||
if (hapd->conf->ssid.wep.default_len) {
|
||||
hostapd_set_privacy(hapd, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (hapd->conf->ssid.wep.key[i] &&
|
||||
hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
|
||||
i == hapd->conf->ssid.wep.idx, NULL, 0,
|
||||
hapd->conf->ssid.wep.key[i],
|
||||
hapd->conf->ssid.wep.len[i])) {
|
||||
wpa_printf(MSG_WARNING, "Could not set WEP "
|
||||
"encryption.");
|
||||
return -1;
|
||||
}
|
||||
if (hapd->conf->ssid.wep.key[i] &&
|
||||
i == hapd->conf->ssid.wep.idx)
|
||||
hostapd_set_privacy(hapd, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Flushing old station entries");
|
||||
if (hostapd_flush(hapd)) {
|
||||
wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
|
||||
ret = -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
hostapd_free_stas(hapd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_validate_bssid_configuration - Validate BSSID configuration
|
||||
* @iface: Pointer to interface data
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function is used to validate that the configured BSSIDs are valid.
|
||||
*/
|
||||
static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
|
||||
{
|
||||
u8 mask[ETH_ALEN] = { 0 };
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
unsigned int i = iface->conf->num_bss, bits = 0, j;
|
||||
int res;
|
||||
int auto_addr = 0;
|
||||
|
||||
if (hostapd_drv_none(hapd))
|
||||
return 0;
|
||||
|
||||
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
|
||||
|
||||
/* Determine the bits necessary to cover the number of BSSIDs. */
|
||||
for (i--; i; i >>= 1)
|
||||
bits++;
|
||||
|
||||
/* Determine the bits necessary to any configured BSSIDs,
|
||||
if they are higher than the number of BSSIDs. */
|
||||
for (j = 0; j < iface->conf->num_bss; j++) {
|
||||
if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
|
||||
if (j)
|
||||
auto_addr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
mask[i] |=
|
||||
iface->conf->bss[j].bssid[i] ^
|
||||
hapd->own_addr[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!auto_addr)
|
||||
goto skip_mask_ext;
|
||||
|
||||
for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
|
||||
;
|
||||
j = 0;
|
||||
if (i < ETH_ALEN) {
|
||||
j = (5 - i) * 8;
|
||||
|
||||
while (mask[i] != 0) {
|
||||
mask[i] >>= 1;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits < j)
|
||||
bits = j;
|
||||
|
||||
if (bits > 40) {
|
||||
wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
|
||||
bits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(mask, 0xff, ETH_ALEN);
|
||||
j = bits / 8;
|
||||
for (i = 5; i > 5 - j; i--)
|
||||
mask[i] = 0;
|
||||
j = bits % 8;
|
||||
while (j--)
|
||||
mask[i] <<= 1;
|
||||
|
||||
skip_mask_ext:
|
||||
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
|
||||
(unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
|
||||
|
||||
res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
|
||||
if (res == 0)
|
||||
return 0;
|
||||
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
|
||||
MACSTR " for start address " MACSTR ".",
|
||||
MAC2STR(mask), MAC2STR(hapd->own_addr));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!auto_addr)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
|
||||
wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
|
||||
" for start address " MACSTR ".",
|
||||
MAC2STR(mask), MAC2STR(hapd->own_addr));
|
||||
wpa_printf(MSG_ERROR, "Start address must be the "
|
||||
"first address in the block (i.e., addr "
|
||||
"AND mask == addr).");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mac_in_conf(struct hostapd_config *conf, const void *a)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++) {
|
||||
if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_bss - Per-BSS setup (initialization)
|
||||
* @hapd: Pointer to BSS data
|
||||
* @first: Whether this BSS is the first BSS of an interface
|
||||
*
|
||||
* This function is used to initialize all per-BSS data structures and
|
||||
* resources. This gets called in a loop for each BSS when an interface is
|
||||
* initialized. Most of the modules that are initialized here will be
|
||||
* deinitialized in hostapd_cleanup().
|
||||
*/
|
||||
static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
{
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
|
||||
int ssid_len, set_ssid;
|
||||
char force_ifname[IFNAMSIZ];
|
||||
u8 if_addr[ETH_ALEN];
|
||||
|
||||
if (!first) {
|
||||
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
|
||||
/* Allocate the next available BSSID. */
|
||||
do {
|
||||
inc_byte_array(hapd->own_addr, ETH_ALEN);
|
||||
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
|
||||
} else {
|
||||
/* Allocate the configured BSSID. */
|
||||
os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
|
||||
|
||||
if (hostapd_mac_comp(hapd->own_addr,
|
||||
hapd->iface->bss[0]->own_addr) ==
|
||||
0) {
|
||||
wpa_printf(MSG_ERROR, "BSS '%s' may not have "
|
||||
"BSSID set to the MAC address of "
|
||||
"the radio", hapd->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
hapd->interface_added = 1;
|
||||
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
|
||||
hapd->conf->iface, hapd->own_addr, hapd,
|
||||
&hapd->drv_priv, force_ifname, if_addr,
|
||||
hapd->conf->bridge[0] ? hapd->conf->bridge :
|
||||
NULL)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
|
||||
MACSTR ")", MAC2STR(hapd->own_addr));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->wmm_enabled < 0)
|
||||
conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
hostapd_flush_old_stations(hapd);
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
|
||||
hostapd_broadcast_wep_clear(hapd);
|
||||
if (hostapd_setup_encryption(hapd->conf->iface, hapd))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Fetch the SSID from the system and use it or,
|
||||
* if one was specified in the config file, verify they
|
||||
* match.
|
||||
*/
|
||||
ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
|
||||
if (ssid_len < 0) {
|
||||
wpa_printf(MSG_ERROR, "Could not read SSID from system");
|
||||
return -1;
|
||||
}
|
||||
if (conf->ssid.ssid_set) {
|
||||
/*
|
||||
* If SSID is specified in the config file and it differs
|
||||
* from what is being used then force installation of the
|
||||
* new SSID.
|
||||
*/
|
||||
set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
|
||||
os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
|
||||
} else {
|
||||
/*
|
||||
* No SSID in the config file; just use the one we got
|
||||
* from the system.
|
||||
*/
|
||||
set_ssid = 0;
|
||||
conf->ssid.ssid_len = ssid_len;
|
||||
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
|
||||
conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
|
||||
}
|
||||
|
||||
if (!hostapd_drv_none(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
|
||||
" and ssid '%s'",
|
||||
hapd->conf->iface, MAC2STR(hapd->own_addr),
|
||||
hapd->conf->ssid.ssid);
|
||||
}
|
||||
|
||||
if (hostapd_setup_wpa_psk(conf)) {
|
||||
wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set SSID for the kernel driver (to be used in beacon and probe
|
||||
* response frames) */
|
||||
if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
|
||||
conf->ssid.ssid_len)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_debug_level == MSG_MSGDUMP)
|
||||
conf->radius->msg_dumps = 1;
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
hapd->radius = radius_client_init(hapd, conf->radius);
|
||||
if (hapd->radius == NULL) {
|
||||
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
if (hostapd_acl_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "ACL initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
if (hostapd_init_wps(hapd, conf))
|
||||
return -1;
|
||||
|
||||
if (authsrv_init(hapd) < 0)
|
||||
return -1;
|
||||
|
||||
if (ieee802_1x_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
|
||||
return -1;
|
||||
|
||||
if (accounting_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "Accounting initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->conf->ieee802_11f &&
|
||||
(hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
|
||||
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
|
||||
"failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->iface->ctrl_iface_init &&
|
||||
hapd->iface->ctrl_iface_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to setup control interface");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ieee802_11_set_beacon(hapd);
|
||||
|
||||
if (hapd->driver && hapd->driver->set_operstate)
|
||||
hapd->driver->set_operstate(hapd->drv_priv, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_tx_queue_params(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
int i;
|
||||
struct hostapd_tx_queue_params *p;
|
||||
|
||||
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||
p = &iface->conf->tx_queue[i];
|
||||
|
||||
if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
|
||||
p->cwmax, p->burst)) {
|
||||
wpa_printf(MSG_DEBUG, "Failed to set TX queue "
|
||||
"parameters for queue %d.", i);
|
||||
/* Continue anyway */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int setup_interface(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
size_t i;
|
||||
char country[4];
|
||||
|
||||
/*
|
||||
* Make sure that all BSSes get configured with a pointer to the same
|
||||
* driver interface.
|
||||
*/
|
||||
for (i = 1; i < iface->num_bss; i++) {
|
||||
iface->bss[i]->driver = hapd->driver;
|
||||
iface->bss[i]->drv_priv = hapd->drv_priv;
|
||||
}
|
||||
|
||||
if (hostapd_validate_bssid_configuration(iface))
|
||||
return -1;
|
||||
|
||||
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
|
||||
os_memcpy(country, hapd->iconf->country, 3);
|
||||
country[3] = '\0';
|
||||
if (hostapd_set_country(hapd, country) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set country code");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (hostapd_get_hw_features(iface)) {
|
||||
/* Not all drivers support this yet, so continue without hw
|
||||
* feature data. */
|
||||
} else {
|
||||
int ret = hostapd_select_hw_mode(iface);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
|
||||
"channel. (%d)", ret);
|
||||
return -1;
|
||||
}
|
||||
ret = hostapd_check_ht_capab(iface);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret == 1) {
|
||||
wpa_printf(MSG_DEBUG, "Interface initialization will "
|
||||
"be completed in a callback");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return hostapd_setup_interface_complete(iface, 0);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
size_t j;
|
||||
u8 *prev_addr;
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "Interface initialization failed");
|
||||
eloop_terminate();
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Completing interface initialization");
|
||||
if (hapd->iconf->channel) {
|
||||
iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
|
||||
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
|
||||
"Frequency: %d MHz",
|
||||
hostapd_hw_mode_txt(hapd->iconf->hw_mode),
|
||||
hapd->iconf->channel, iface->freq);
|
||||
|
||||
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
|
||||
hapd->iconf->channel,
|
||||
hapd->iconf->ieee80211n,
|
||||
hapd->iconf->secondary_channel)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set channel for "
|
||||
"kernel driver");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (iface->current_mode) {
|
||||
if (hostapd_prepare_rates(hapd, iface->current_mode)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to prepare rates "
|
||||
"table.");
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Failed to prepare rates table.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (hapd->iconf->rts_threshold > -1 &&
|
||||
hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
|
||||
"kernel driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->iconf->fragm_threshold > -1 &&
|
||||
hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
|
||||
"for kernel driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
prev_addr = hapd->own_addr;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
if (j)
|
||||
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
|
||||
if (hostapd_setup_bss(hapd, j == 0))
|
||||
return -1;
|
||||
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
|
||||
prev_addr = hapd->own_addr;
|
||||
}
|
||||
|
||||
hostapd_tx_queue_params(iface);
|
||||
|
||||
ap_list_init(iface);
|
||||
|
||||
if (hostapd_driver_commit(hapd) < 0) {
|
||||
wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
|
||||
"configuration", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
|
||||
iface->bss[0]->conf->iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_interface - Setup of an interface
|
||||
* @iface: Pointer to interface data.
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Initializes the driver interface, validates the configuration,
|
||||
* and sets driver parameters based on the configuration.
|
||||
* Flushes old stations, sets the channel, encryption,
|
||||
* beacons, and WDS links based on the configuration.
|
||||
*/
|
||||
int hostapd_setup_interface(struct hostapd_iface *iface)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = setup_interface(iface);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
|
||||
iface->bss[0]->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_alloc_bss_data - Allocate and initialize per-BSS data
|
||||
* @hapd_iface: Pointer to interface data
|
||||
* @conf: Pointer to per-interface configuration
|
||||
* @bss: Pointer to per-BSS configuration for this BSS
|
||||
* Returns: Pointer to allocated BSS data
|
||||
*
|
||||
* This function is used to allocate per-BSS data structure. This data will be
|
||||
* freed after hostapd_cleanup() is called for it during interface
|
||||
* deinitialization.
|
||||
*/
|
||||
struct hostapd_data *
|
||||
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss)
|
||||
{
|
||||
struct hostapd_data *hapd;
|
||||
|
||||
hapd = os_zalloc(sizeof(*hapd));
|
||||
if (hapd == NULL)
|
||||
return NULL;
|
||||
|
||||
hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
|
||||
hapd->iconf = conf;
|
||||
hapd->conf = bss;
|
||||
hapd->iface = hapd_iface;
|
||||
hapd->driver = hapd->iconf->driver;
|
||||
|
||||
return hapd;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
if (iface == NULL)
|
||||
return;
|
||||
|
||||
hostapd_cleanup_iface_pre(iface);
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
struct hostapd_data *hapd = iface->bss[j];
|
||||
hostapd_free_stas(hapd);
|
||||
hostapd_flush_old_stations(hapd);
|
||||
hostapd_cleanup(hapd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hostapd_interface_free(struct hostapd_iface *iface)
|
||||
{
|
||||
size_t j;
|
||||
for (j = 0; j < iface->num_bss; j++)
|
||||
os_free(iface->bss[j]);
|
||||
hostapd_cleanup_iface(iface);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
|
||||
* @hapd: Pointer to BSS data
|
||||
* @sta: Pointer to the associated STA data
|
||||
* @reassoc: 1 to indicate this was a re-association; 0 = first association
|
||||
*
|
||||
* This function will be called whenever a station associates with the AP. It
|
||||
* can be called from ieee802_11.c for drivers that export MLME to hostapd and
|
||||
* from drv_callbacks.c based on driver events for drivers that take care of
|
||||
* management frames (IEEE 802.11 authentication and association) internally.
|
||||
*/
|
||||
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int reassoc)
|
||||
{
|
||||
if (hapd->tkip_countermeasures) {
|
||||
hostapd_drv_sta_deauth(hapd, sta->addr,
|
||||
WLAN_REASON_MICHAEL_MIC_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_prune_associations(hapd, sta->addr);
|
||||
|
||||
/* IEEE 802.11F (IAPP) */
|
||||
if (hapd->conf->ieee802_11f)
|
||||
iapp_new_station(hapd->iapp, sta);
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
|
||||
sta->no_p2p_set = 1;
|
||||
hapd->num_sta_no_p2p++;
|
||||
if (hapd->num_sta_no_p2p == 1)
|
||||
hostapd_p2p_non_p2p_sta_connected(hapd);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
/* Start accounting here, if IEEE 802.1X and WPA are not used.
|
||||
* IEEE 802.1X/WPA code will start accounting after the station has
|
||||
* been authorized. */
|
||||
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
|
||||
accounting_sta_start(hapd, sta);
|
||||
|
||||
/* Start IEEE 802.1X authentication process for new stations */
|
||||
ieee802_1x_new_station(hapd, sta);
|
||||
if (reassoc) {
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
|
||||
} else
|
||||
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
|
||||
}
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* hostapd / Initialization and configuration
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef HOSTAPD_H
|
||||
#define HOSTAPD_H
|
||||
|
||||
#include "common/defs.h"
|
||||
|
||||
struct wpa_driver_ops;
|
||||
struct wpa_ctrl_dst;
|
||||
struct radius_server_data;
|
||||
struct upnp_wps_device_sm;
|
||||
struct hapd_interfaces;
|
||||
struct hostapd_data;
|
||||
struct sta_info;
|
||||
struct hostap_sta_driver_data;
|
||||
struct ieee80211_ht_capabilities;
|
||||
struct full_dynamic_vlan;
|
||||
enum wps_event;
|
||||
union wps_event_data;
|
||||
|
||||
struct hostapd_probereq_cb {
|
||||
int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
#define HOSTAPD_RATE_BASIC 0x00000001
|
||||
|
||||
struct hostapd_rate_data {
|
||||
int rate; /* rate in 100 kbps */
|
||||
int flags; /* HOSTAPD_RATE_ flags */
|
||||
};
|
||||
|
||||
struct hostapd_frame_info {
|
||||
u32 channel;
|
||||
u32 datarate;
|
||||
u32 ssi_signal;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
#define STA_HASH_SIZE 256
|
||||
#define STA_HASH(sta) (sta[5])
|
||||
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||
|
||||
/*
|
||||
* Bitfield for indicating which AIDs are allocated. Only AID values
|
||||
* 1-2007 are used and as such, the bit at index 0 corresponds to AID
|
||||
* 1.
|
||||
*/
|
||||
#define AID_WORDS ((2008 + 31) / 32)
|
||||
u32 sta_aid[AID_WORDS];
|
||||
|
||||
const struct wpa_driver_ops *driver;
|
||||
void *drv_priv;
|
||||
|
||||
void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int reassoc);
|
||||
|
||||
void *msg_ctx; /* ctx for wpa_msg() calls */
|
||||
|
||||
struct radius_client_data *radius;
|
||||
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;
|
||||
|
||||
struct wpabuf *wps_beacon_ie;
|
||||
struct wpabuf *wps_probe_resp_ie;
|
||||
#ifdef CONFIG_WPS
|
||||
unsigned int ap_pin_failures;
|
||||
struct upnp_wps_device_sm *wps_upnp;
|
||||
unsigned int ap_pin_lockout_time;
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
struct hostapd_probereq_cb *probereq_cb;
|
||||
size_t num_probereq_cb;
|
||||
|
||||
void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
|
||||
int freq);
|
||||
void *public_action_cb_ctx;
|
||||
|
||||
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
|
||||
int freq);
|
||||
void *vendor_action_cb_ctx;
|
||||
|
||||
void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
|
||||
const u8 *uuid_e);
|
||||
void *wps_reg_success_cb_ctx;
|
||||
|
||||
void (*wps_event_cb)(void *ctx, enum wps_event event,
|
||||
union wps_event_data *data);
|
||||
void *wps_event_cb_ctx;
|
||||
|
||||
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
|
||||
int authorized);
|
||||
void *sta_authorized_cb_ctx;
|
||||
|
||||
void (*setup_complete_cb)(void *ctx);
|
||||
void *setup_complete_cb_ctx;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
struct p2p_data *p2p;
|
||||
struct p2p_group *p2p_group;
|
||||
struct wpabuf *p2p_beacon_ie;
|
||||
struct wpabuf *p2p_probe_resp_ie;
|
||||
|
||||
/* Number of non-P2P association stations */
|
||||
int num_sta_no_p2p;
|
||||
|
||||
/* Periodic NoA (used only when no non-P2P clients in the group) */
|
||||
int noa_enabled;
|
||||
int noa_start;
|
||||
int noa_duration;
|
||||
#endif /* CONFIG_P2P */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct hostapd_iface - hostapd per-interface data structure
|
||||
*/
|
||||
struct hostapd_iface {
|
||||
struct hapd_interfaces *interfaces;
|
||||
void *owner;
|
||||
int (*reload_config)(struct hostapd_iface *iface);
|
||||
struct hostapd_config * (*config_read_cb)(const char *config_fname);
|
||||
char *config_fname;
|
||||
struct hostapd_config *conf;
|
||||
|
||||
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;
|
||||
|
||||
unsigned int drv_flags;
|
||||
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;
|
||||
int freq;
|
||||
|
||||
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;
|
||||
|
||||
u16 ht_op_mode;
|
||||
void (*scan_cb)(struct hostapd_iface *iface);
|
||||
|
||||
int (*ctrl_iface_init)(struct hostapd_data *hapd);
|
||||
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
|
||||
|
||||
int (*for_each_interface)(struct hapd_interfaces *interfaces,
|
||||
int (*cb)(struct hostapd_iface *iface,
|
||||
void *ctx), void *ctx);
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
int hostapd_reload_config(struct hostapd_iface *iface);
|
||||
struct hostapd_data *
|
||||
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss);
|
||||
int hostapd_setup_interface(struct hostapd_iface *iface);
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
|
||||
void hostapd_interface_deinit(struct hostapd_iface *iface);
|
||||
void hostapd_interface_free(struct hostapd_iface *iface);
|
||||
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int reassoc);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
int (*cb)(void *ctx, const u8 *sa,
|
||||
const u8 *ie, size_t ie_len),
|
||||
void *ctx);
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
|
||||
|
||||
/* drv_callbacks.c (TODO: move to somewhere else?) */
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *ie, size_t ielen, int reassoc);
|
||||
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
|
||||
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
|
||||
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
|
||||
const u8 *ie, size_t ie_len);
|
||||
|
||||
#endif /* HOSTAPD_H */
|
|
@ -1,754 +0,0 @@
|
|||
/*
|
||||
* hostapd / Hardware feature query and different modes
|
||||
* Copyright 2002-2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "hw_features.h"
|
||||
|
||||
|
||||
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
size_t num_hw_features)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (hw_features == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_hw_features; i++) {
|
||||
os_free(hw_features[i].channels);
|
||||
os_free(hw_features[i].rates);
|
||||
}
|
||||
|
||||
os_free(hw_features);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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_zalloc(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]))
|
||||
continue;
|
||||
|
||||
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
|
||||
rate->rate = mode->rates[i];
|
||||
if (hostapd_rate_found(basic_rates, rate->rate)) {
|
||||
rate->flags |= HOSTAPD_RATE_BASIC;
|
||||
num_basic_rates++;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
|
||||
hapd->iface->num_rates, rate->rate, rate->flags);
|
||||
hapd->iface->num_rates++;
|
||||
}
|
||||
|
||||
if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) &&
|
||||
(!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) {
|
||||
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 void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
|
||||
{
|
||||
if (iface->conf->secondary_channel > 0) {
|
||||
iface->conf->channel += 4;
|
||||
iface->conf->secondary_channel = -1;
|
||||
} else {
|
||||
iface->conf->channel -= 4;
|
||||
iface->conf->secondary_channel = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
|
||||
int *pri_chan, int *sec_chan)
|
||||
{
|
||||
struct ieee80211_ht_operation *oper;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
*pri_chan = *sec_chan = 0;
|
||||
|
||||
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
|
||||
if (elems.ht_operation &&
|
||||
elems.ht_operation_len >= sizeof(*oper)) {
|
||||
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
|
||||
*pri_chan = oper->control_chan;
|
||||
if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
|
||||
int sec = oper->ht_param &
|
||||
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
|
||||
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
|
||||
*sec_chan = *pri_chan + 4;
|
||||
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
|
||||
*sec_chan = *pri_chan - 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
|
||||
struct wpa_scan_results *scan_res)
|
||||
{
|
||||
int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
|
||||
int bss_pri_chan, bss_sec_chan;
|
||||
size_t i;
|
||||
int match;
|
||||
|
||||
pri_chan = iface->conf->channel;
|
||||
sec_chan = iface->conf->secondary_channel * 4;
|
||||
pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
|
||||
if (iface->conf->secondary_channel > 0)
|
||||
sec_freq = pri_freq + 20;
|
||||
else
|
||||
sec_freq = pri_freq - 20;
|
||||
|
||||
/*
|
||||
* Switch PRI/SEC channels if Beacons were detected on selected SEC
|
||||
* channel, but not on selected PRI channel.
|
||||
*/
|
||||
pri_bss = sec_bss = 0;
|
||||
for (i = 0; i < scan_res->num; i++) {
|
||||
struct wpa_scan_res *bss = scan_res->res[i];
|
||||
if (bss->freq == pri_freq)
|
||||
pri_bss++;
|
||||
else if (bss->freq == sec_freq)
|
||||
sec_bss++;
|
||||
}
|
||||
if (sec_bss && !pri_bss) {
|
||||
wpa_printf(MSG_INFO, "Switch own primary and secondary "
|
||||
"channel to get secondary channel with no Beacons "
|
||||
"from other BSSes");
|
||||
ieee80211n_switch_pri_sec(iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match PRI/SEC channel with any existing HT40 BSS on the same
|
||||
* channels that we are about to use (if already mixed order in
|
||||
* existing BSSes, use own preference).
|
||||
*/
|
||||
match = 0;
|
||||
for (i = 0; i < scan_res->num; i++) {
|
||||
struct wpa_scan_res *bss = scan_res->res[i];
|
||||
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
|
||||
if (pri_chan == bss_pri_chan &&
|
||||
sec_chan == bss_sec_chan) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
for (i = 0; i < scan_res->num; i++) {
|
||||
struct wpa_scan_res *bss = scan_res->res[i];
|
||||
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
|
||||
&bss_sec_chan);
|
||||
if (pri_chan == bss_sec_chan &&
|
||||
sec_chan == bss_pri_chan) {
|
||||
wpa_printf(MSG_INFO, "Switch own primary and "
|
||||
"secondary channel due to BSS "
|
||||
"overlap with " MACSTR,
|
||||
MAC2STR(bss->bssid));
|
||||
ieee80211n_switch_pri_sec(iface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
|
||||
struct wpa_scan_results *scan_res)
|
||||
{
|
||||
int pri_freq, sec_freq;
|
||||
int affected_start, affected_end;
|
||||
size_t i;
|
||||
|
||||
pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
|
||||
if (iface->conf->secondary_channel > 0)
|
||||
sec_freq = pri_freq + 20;
|
||||
else
|
||||
sec_freq = pri_freq - 20;
|
||||
affected_start = (pri_freq + sec_freq) / 2 - 25;
|
||||
affected_end = (pri_freq + sec_freq) / 2 + 25;
|
||||
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
|
||||
affected_start, affected_end);
|
||||
for (i = 0; i < scan_res->num; i++) {
|
||||
struct wpa_scan_res *bss = scan_res->res[i];
|
||||
int pri = bss->freq;
|
||||
int sec = pri;
|
||||
int sec_chan, pri_chan;
|
||||
|
||||
ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
|
||||
|
||||
if (sec_chan) {
|
||||
if (sec_chan < pri_chan)
|
||||
sec = pri - 20;
|
||||
else
|
||||
sec = pri + 20;
|
||||
}
|
||||
|
||||
if ((pri < affected_start || pri > affected_end) &&
|
||||
(sec < affected_start || sec > affected_end))
|
||||
continue; /* not within affected channel range */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
|
||||
" freq=%d pri=%d sec=%d",
|
||||
MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
|
||||
|
||||
if (sec_chan) {
|
||||
if (pri_freq != pri || sec_freq != sec) {
|
||||
wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
|
||||
"mismatch with BSS " MACSTR
|
||||
" <%d,%d> (chan=%d%c) vs. <%d,%d>",
|
||||
MAC2STR(bss->bssid),
|
||||
pri, sec, pri_chan,
|
||||
sec > pri ? '+' : '-',
|
||||
pri_freq, sec_freq);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: 40 MHz intolerant */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_scan_results_free(struct wpa_scan_results *res)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (res == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < res->num; i++)
|
||||
os_free(res->res[i]);
|
||||
os_free(res->res);
|
||||
os_free(res);
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211n_check_scan(struct hostapd_iface *iface)
|
||||
{
|
||||
struct wpa_scan_results *scan_res;
|
||||
int oper40;
|
||||
int res;
|
||||
|
||||
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
|
||||
* allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
|
||||
|
||||
iface->scan_cb = NULL;
|
||||
|
||||
scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
|
||||
if (scan_res == NULL) {
|
||||
hostapd_setup_interface_complete(iface, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
|
||||
oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
|
||||
else
|
||||
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
|
||||
wpa_scan_results_free(scan_res);
|
||||
|
||||
if (!oper40) {
|
||||
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
|
||||
"channel pri=%d sec=%d based on overlapping BSSes",
|
||||
iface->conf->channel,
|
||||
iface->conf->channel +
|
||||
iface->conf->secondary_channel * 4);
|
||||
iface->conf->secondary_channel = 0;
|
||||
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
|
||||
}
|
||||
|
||||
res = ieee80211n_allowed_ht40_channel_pair(iface);
|
||||
hostapd_setup_interface_complete(iface, !res);
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||
{
|
||||
struct wpa_driver_scan_params params;
|
||||
|
||||
if (!iface->conf->secondary_channel)
|
||||
return 0; /* HT40 not used */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
|
||||
"40 MHz channel");
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
/* TODO: scan only the needed frequency */
|
||||
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
|
||||
wpa_printf(MSG_ERROR, "Failed to request a scan of "
|
||||
"neighboring BSSes");
|
||||
|
||||
//DRIVER_RTW Modify
|
||||
//return -1;
|
||||
return 0;//ignore this error
|
||||
}
|
||||
|
||||
iface->scan_cb = ieee80211n_check_scan;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||
{
|
||||
u16 hw = iface->current_mode->ht_capab;
|
||||
u16 conf = iface->conf->ht_capab;
|
||||
|
||||
if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
|
||||
!(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
|
||||
wpa_printf(MSG_ERROR, "Driver does not support configured "
|
||||
"HT capability [LDPC]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
int ret;
|
||||
if (!iface->conf->ieee80211n)
|
||||
return 0;
|
||||
if (!ieee80211n_supported_ht_capab(iface))
|
||||
return -1;
|
||||
ret = ieee80211n_check_40mhz(iface);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!ieee80211n_allowed_ht40_channel_pair(iface))
|
||||
return -1;
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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 == 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 && iface->conf->secondary_channel) {
|
||||
int sec_ok = 0;
|
||||
int sec_chan = iface->conf->channel +
|
||||
iface->conf->secondary_channel * 4;
|
||||
for (j = 0; j < iface->current_mode->num_channels; j++) {
|
||||
struct hostapd_channel_data *chan =
|
||||
&iface->current_mode->channels[j];
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
(chan->chan == sec_chan)) {
|
||||
sec_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sec_ok) {
|
||||
hostapd_logger(iface->bss[0], NULL,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"Configured HT40 secondary channel "
|
||||
"(%d) not found from the channel list "
|
||||
"of current mode (%d) %s",
|
||||
sec_chan, iface->current_mode->mode,
|
||||
hostapd_hw_mode_txt(
|
||||
iface->current_mode->mode));
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
if (iface->conf->channel == 0) {
|
||||
/* TODO: could request a scan of neighboring BSSes and select
|
||||
* the channel automatically */
|
||||
wpa_printf(MSG_ERROR, "Channel not configured "
|
||||
"(hw_mode/channel in hostapd.conf)");
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* hostapd / IEEE 802.11 Management
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_H
|
||||
#define IEEE802_11_H
|
||||
|
||||
struct hostapd_iface;
|
||||
struct hostapd_data;
|
||||
struct sta_info;
|
||||
struct hostapd_frame_info;
|
||||
struct ieee80211_ht_capabilities;
|
||||
|
||||
void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
struct hostapd_frame_info *fi);
|
||||
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
u16 stype, int ok);
|
||||
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
|
||||
#ifdef NEED_AP_MLME
|
||||
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);
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int probe);
|
||||
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
int hostapd_ht_operation_update(struct hostapd_iface *iface);
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *trans_id);
|
||||
void hostapd_get_ht_capab(struct hostapd_data *hapd,
|
||||
struct ieee80211_ht_capabilities *ht_cap,
|
||||
struct ieee80211_ht_capabilities *neg_ht_cap);
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab, size_t ht_capab_len);
|
||||
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len, int ack);
|
||||
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
|
||||
int wds);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
* hostapd / IEEE 802.11n HT
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2008, Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "sta_info.h"
|
||||
#include "beacon.h"
|
||||
#include "ieee802_11.h"
|
||||
|
||||
|
||||
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_ht_capabilities *cap;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
|
||||
hapd->conf->disable_11n)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_HT_CAP;
|
||||
*pos++ = sizeof(*cap);
|
||||
|
||||
cap = (struct ieee80211_ht_capabilities *) pos;
|
||||
os_memset(cap, 0, sizeof(*cap));
|
||||
cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab);
|
||||
cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params;
|
||||
os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set,
|
||||
16);
|
||||
|
||||
/* TODO: ht_extended_capabilities (now fully disabled) */
|
||||
/* TODO: tx_bf_capability_info (now fully disabled) */
|
||||
/* TODO: asel_capabilities (now fully disabled) */
|
||||
|
||||
pos += sizeof(*cap);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_ht_operation *oper;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_HT_OPERATION;
|
||||
*pos++ = sizeof(*oper);
|
||||
|
||||
oper = (struct ieee80211_ht_operation *) pos;
|
||||
os_memset(oper, 0, sizeof(*oper));
|
||||
|
||||
oper->control_chan = hapd->iconf->channel;
|
||||
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
|
||||
if (hapd->iconf->secondary_channel == 1)
|
||||
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
|
||||
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
|
||||
if (hapd->iconf->secondary_channel == -1)
|
||||
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
|
||||
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
|
||||
|
||||
pos += sizeof(*oper);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
op_mode
|
||||
Set to 0 (HT pure) under the followign conditions
|
||||
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
|
||||
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
|
||||
Set to 1 (HT non-member protection) if there may be non-HT STAs
|
||||
in both the primary and the secondary channel
|
||||
Set to 2 if only HT STAs are associated in BSS,
|
||||
however and at least one 20 MHz HT STA is associated
|
||||
Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
|
||||
*/
|
||||
int hostapd_ht_operation_update(struct hostapd_iface *iface)
|
||||
{
|
||||
u16 cur_op_mode, new_op_mode;
|
||||
int op_mode_changes = 0;
|
||||
|
||||
if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
|
||||
__func__, iface->ht_op_mode);
|
||||
|
||||
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
|
||||
&& iface->num_sta_ht_no_gf) {
|
||||
iface->ht_op_mode |=
|
||||
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
|
||||
op_mode_changes++;
|
||||
} else if ((iface->ht_op_mode &
|
||||
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
|
||||
iface->num_sta_ht_no_gf == 0) {
|
||||
iface->ht_op_mode &=
|
||||
~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
|
||||
op_mode_changes++;
|
||||
}
|
||||
|
||||
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
|
||||
(iface->num_sta_no_ht || iface->olbc_ht)) {
|
||||
iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
|
||||
op_mode_changes++;
|
||||
} else if ((iface->ht_op_mode &
|
||||
HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
|
||||
(iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
|
||||
iface->ht_op_mode &=
|
||||
~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
|
||||
op_mode_changes++;
|
||||
}
|
||||
|
||||
new_op_mode = 0;
|
||||
if (iface->num_sta_no_ht)
|
||||
new_op_mode = OP_MODE_MIXED;
|
||||
else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
|
||||
&& iface->num_sta_ht_20mhz)
|
||||
new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
|
||||
else if (iface->olbc_ht)
|
||||
new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
|
||||
else
|
||||
new_op_mode = OP_MODE_PURE;
|
||||
|
||||
cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
|
||||
if (cur_op_mode != new_op_mode) {
|
||||
iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
|
||||
iface->ht_op_mode |= new_op_mode;
|
||||
op_mode_changes++;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
|
||||
__func__, iface->ht_op_mode, op_mode_changes);
|
||||
|
||||
return op_mode_changes;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab, size_t ht_capab_len)
|
||||
{
|
||||
/* Disable HT caps for STAs associated to no-HT BSSes. */
|
||||
if (!ht_capab ||
|
||||
ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
|
||||
hapd->conf->disable_11n) {
|
||||
sta->flags &= ~WLAN_STA_HT;
|
||||
os_free(sta->ht_capabilities);
|
||||
sta->ht_capabilities = NULL;
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (sta->ht_capabilities == NULL) {
|
||||
sta->ht_capabilities =
|
||||
os_zalloc(sizeof(struct ieee80211_ht_capabilities));
|
||||
if (sta->ht_capabilities == NULL)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
sta->flags |= WLAN_STA_HT;
|
||||
os_memcpy(sta->ht_capabilities, ht_capab,
|
||||
sizeof(struct ieee80211_ht_capabilities));
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
u16 ht_capab;
|
||||
|
||||
ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
|
||||
wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: "
|
||||
"0x%04x", MAC2STR(sta->addr), ht_capab);
|
||||
if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
|
||||
if (!sta->no_ht_gf_set) {
|
||||
sta->no_ht_gf_set = 1;
|
||||
hapd->iface->num_sta_ht_no_gf++;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num "
|
||||
"of non-gf stations %d",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
hapd->iface->num_sta_ht_no_gf);
|
||||
}
|
||||
if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
|
||||
if (!sta->ht_20mhz_set) {
|
||||
sta->ht_20mhz_set = 1;
|
||||
hapd->iface->num_sta_ht_20mhz++;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of "
|
||||
"20MHz HT STAs %d",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
hapd->iface->num_sta_ht_20mhz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if (!sta->no_ht_set) {
|
||||
sta->no_ht_set = 1;
|
||||
hapd->iface->num_sta_no_ht++;
|
||||
}
|
||||
if (hapd->iconf->ieee80211n) {
|
||||
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of "
|
||||
"non-HT stations %d",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
hapd->iface->num_sta_no_ht);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
|
||||
update_sta_ht(hapd, sta);
|
||||
else
|
||||
update_sta_no_ht(hapd, sta);
|
||||
|
||||
if (hostapd_ht_operation_update(hapd->iface) > 0)
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_ht_capab(struct hostapd_data *hapd,
|
||||
struct ieee80211_ht_capabilities *ht_cap,
|
||||
struct ieee80211_ht_capabilities *neg_ht_cap)
|
||||
{
|
||||
u16 cap;
|
||||
|
||||
if (ht_cap == NULL)
|
||||
return;
|
||||
os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
|
||||
cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
|
||||
cap &= hapd->iconf->ht_capab;
|
||||
cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
|
||||
|
||||
/*
|
||||
* STBC needs to be handled specially
|
||||
* if we don't support RX STBC, mask out TX STBC in the STA's HT caps
|
||||
* if we don't support TX STBC, mask out RX STBC in the STA's HT caps
|
||||
*/
|
||||
if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK))
|
||||
cap &= ~HT_CAP_INFO_TX_STBC;
|
||||
if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC))
|
||||
cap &= ~HT_CAP_INFO_RX_STBC_MASK;
|
||||
|
||||
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
/*
|
||||
* hostapd - PeerKey for Direct Link Setup (DLS)
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wpa_auth_i.h"
|
||||
#include "wpa_auth_ie.h"
|
||||
|
||||
#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 (random_get_bytes(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 */
|
|
@ -1,425 +0,0 @@
|
|||
/*
|
||||
* 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 "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_config.h"
|
||||
#include "pmksa_cache_auth.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;
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_free_class(&entry->radius_class);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_copy_class(&entry->radius_class, &eapol->radius_class);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
entry->eap_type_authsrv = eapol->eap_type_authsrv;
|
||||
entry->vlan_id = ((struct sta_info *) 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);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_free_class(&eapol->radius_class);
|
||||
radius_copy_class(&eapol->radius_class, &entry->radius_class);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
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;
|
||||
((struct sta_info *) 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_auth_add - Add a PMKSA cache entry
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_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_auth_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_auth_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);
|
||||
}
|
||||
}
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
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_auth_deinit - Free all entries in PMKSA cache
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
*/
|
||||
void pmksa_cache_auth_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_auth_get - Fetch a PMKSA cache entry
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_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_auth_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_auth_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_auth_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_auth_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;
|
||||
}
|
|
@ -1,796 +0,0 @@
|
|||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "hostapd.h"
|
||||
#include "accounting.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "preauth_auth.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
#include "ap_mlme.h"
|
||||
#include "vlan_init.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
#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);
|
||||
|
||||
/* just in case */
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
|
||||
if (sta->flags & WLAN_STA_WDS)
|
||||
hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
|
||||
|
||||
if (!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_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) / 32] &=
|
||||
~BIT((sta->aid - 1) % 32);
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (sta->no_p2p_set) {
|
||||
sta->no_p2p_set = 0;
|
||||
hapd->num_sta_no_p2p--;
|
||||
if (hapd->num_sta_no_p2p == 0)
|
||||
hostapd_p2p_non_p2p_sta_disconnected(hapd);
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
|
||||
if (hostapd_ht_operation_update(hapd->iface) > 0)
|
||||
set_beacon++;
|
||||
#endif /* NEED_AP_MLME && 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);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
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 */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
wpabuf_free(sta->wps_ie);
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
|
||||
os_free(sta->ht_capabilities);
|
||||
|
||||
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;
|
||||
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
|
||||
if (inactive_sec == -1) {
|
||||
wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
|
||||
"get station info rom 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_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
|
||||
"active %is ago",
|
||||
MAC2STR(sta->addr), inactive_sec);
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
next_time = hapd->conf->ap_max_inactivity -
|
||||
inactive_sec;
|
||||
} else {
|
||||
wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
|
||||
"inactive too long: %d sec, max allowed: %d",
|
||||
MAC2STR(sta->addr), inactive_sec,
|
||||
hapd->conf->ap_max_inactivity);
|
||||
}
|
||||
}
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
sta->timeout_next == STA_DISASSOC &&
|
||||
!(sta->flags & WLAN_STA_PENDING_POLL)) {
|
||||
wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
|
||||
"poll", MAC2STR(sta->addr));
|
||||
/* data nullfunc frame poll did not produce TX errors; assume
|
||||
* station ACKed it */
|
||||
sta->timeout_next = STA_NULLFUNC;
|
||||
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)) {
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
/* send data frame to poll STA and check whether this frame
|
||||
* is ACKed */
|
||||
struct ieee80211_hdr hdr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, " Polling STA with data frame");
|
||||
sta->flags |= WLAN_STA_PENDING_POLL;
|
||||
|
||||
os_memset(&hdr, 0, sizeof(hdr));
|
||||
if (hapd->driver &&
|
||||
os_strcmp(hapd->driver->name, "hostap") == 0) {
|
||||
/*
|
||||
* WLAN_FC_STYPE_NULLFUNC would be more appropriate,
|
||||
* but it is apparently not retried so TX Exc events
|
||||
* are not received for it.
|
||||
*/
|
||||
hdr.frame_control =
|
||||
IEEE80211_FC(WLAN_FC_TYPE_DATA,
|
||||
WLAN_FC_STYPE_DATA);
|
||||
} else {
|
||||
hdr.frame_control =
|
||||
IEEE80211_FC(WLAN_FC_TYPE_DATA,
|
||||
WLAN_FC_STYPE_NULLFUNC);
|
||||
}
|
||||
|
||||
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
|
||||
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
|
||||
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
|
||||
|
||||
if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 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_drv_sta_deauth(
|
||||
hapd, sta->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
} else {
|
||||
hostapd_drv_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_drv_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->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;
|
||||
ap_sta_remove_in_other_bss(hapd, sta);
|
||||
|
||||
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_drv_sta_remove(hapd, sta->addr) &&
|
||||
sta->flags & WLAN_STA_ASSOC) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
|
||||
" from kernel driver.", MAC2STR(sta->addr));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
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)
|
||||
continue;
|
||||
|
||||
ap_sta_disconnect(bss, sta2, sta2->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 reason)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
sta->flags &= ~WLAN_STA_ASSOC;
|
||||
ap_sta_remove(hapd, sta);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
const char *iface;
|
||||
struct hostapd_vlan *vlan = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do not proceed furthur if the vlan id remains same. We do not want
|
||||
* duplicate dynamic vlan entries.
|
||||
*/
|
||||
if (sta->vlan_id == old_vlanid)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* 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");
|
||||
|
||||
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
|
||||
if (ret < 0) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
|
||||
"entry to vlan_id=%d", sta->vlan_id);
|
||||
}
|
||||
return ret;
|
||||
#else /* CONFIG_NO_VLAN */
|
||||
return 0;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
}
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int authorized)
|
||||
{
|
||||
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
|
||||
return;
|
||||
|
||||
if (authorized)
|
||||
sta->flags |= WLAN_STA_AUTHORIZED;
|
||||
else
|
||||
sta->flags &= ~WLAN_STA_AUTHORIZED;
|
||||
|
||||
if (hapd->sta_authorized_cb)
|
||||
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
|
||||
sta->addr, authorized);
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason)
|
||||
{
|
||||
|
||||
if (sta == NULL && addr)
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (addr)
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
|
||||
if (sta == NULL)
|
||||
return;
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* hostapd / Station table
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef STA_INFO_H
|
||||
#define STA_INFO_H
|
||||
|
||||
/* 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_WMM 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_WDS BIT(14)
|
||||
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
|
||||
#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; /* Bitfield of WLAN_STA_* */
|
||||
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;
|
||||
unsigned int no_p2p_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;
|
||||
|
||||
struct ieee80211_ht_capabilities *ht_capabilities;
|
||||
|
||||
#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 */
|
||||
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
|
||||
};
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
|
||||
struct hostapd_data;
|
||||
|
||||
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);
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason);
|
||||
|
||||
void ap_sta_set_authorized(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int authorized);
|
||||
static inline int ap_sta_is_authorized(struct sta_info *sta)
|
||||
{
|
||||
return sta->flags & WLAN_STA_AUTHORIZED;
|
||||
}
|
||||
|
||||
#endif /* STA_INFO_H */
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* hostapd / TKIP countermeasures
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef TKIP_COUNTERMEASURES_H
|
||||
#define TKIP_COUNTERMEASURES_H
|
||||
|
||||
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
|
||||
|
||||
#endif /* TKIP_COUNTERMEASURES_H */
|
|
@ -1,905 +0,0 @@
|
|||
/*
|
||||
* hostapd / VLAN initialization
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.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 "drivers/priv_netlink.h"
|
||||
#include "utils/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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
|
||||
"for interface %s: %s",
|
||||
__func__, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (up)
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
|
||||
"for interface %s (up=%d): %s",
|
||||
__func__, if_name, up, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_up(const char *if_name)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
|
||||
return ifconfig_helper(if_name, 1);
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_down(const char *if_name)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", 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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
|
||||
"interface index for '%s'",
|
||||
__func__, 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. */
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
|
||||
"BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
|
||||
"%s", __func__, br_name, if_name, strerror(errno));
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
|
||||
"interface index for '%s'",
|
||||
__func__, 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;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
|
||||
"BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
|
||||
"%s", __func__, br_name, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int br_delbr(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned long arg[2];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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. */
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
|
||||
"%s: %s", __func__, br_name, strerror(errno));
|
||||
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[4];
|
||||
struct ifreq ifr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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 {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
|
||||
"failed for %s: %s",
|
||||
__func__, br_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrease forwarding delay to avoid EAPOL timeouts. */
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
|
||||
arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
|
||||
arg[1] = 1;
|
||||
arg[2] = 0;
|
||||
arg[3] = 0;
|
||||
ifr.ifr_data = (char *) &arg;
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: "
|
||||
"BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
|
||||
"%s: %s", __func__, br_name, strerror(errno));
|
||||
/* Continue anyway */
|
||||
}
|
||||
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
|
||||
"failed for %s: %s",
|
||||
__func__, br_name, strerror(errno));
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
|
||||
if_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
|
||||
"%s", __func__, if_name, strerror(errno));
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
|
||||
if_name, vid);
|
||||
ifconfig_up(if_name);
|
||||
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
|
||||
if_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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);
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
|
||||
"if_name %s exists already",
|
||||
if_request.device1);
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
|
||||
"%s",
|
||||
__func__, if_request.device1, strerror(errno));
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
|
||||
name_type);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
|
||||
"name_type=%u failed: %s",
|
||||
__func__, name_type, strerror(errno));
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
|
||||
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
|
||||
|
||||
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 (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
|
||||
br_delif(br_name, vlan->ifname);
|
||||
|
||||
if (tagged_interface) {
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
|
||||
"vlan%d", vlan->vlan_id);
|
||||
if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
|
||||
br_delif(br_name, vlan_ifname);
|
||||
ifconfig_down(vlan_ifname);
|
||||
|
||||
if (vlan->clean & DVLAN_CLEAN_VLAN)
|
||||
vlan_rem(vlan_ifname);
|
||||
}
|
||||
|
||||
if ((vlan->clean & DVLAN_CLEAN_BR) &&
|
||||
br_getnumports(br_name) == 0) {
|
||||
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)
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
|
||||
__func__, strerror(errno));
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "VLAN: 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) {
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
|
||||
"netlink message", __func__, 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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
|
||||
"NETLINK_ROUTE) failed: %s",
|
||||
__func__, strerror(errno));
|
||||
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) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
|
||||
__func__, strerror(errno));
|
||||
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_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
|
||||
i == mssid->wep.idx, NULL, 0,
|
||||
mssid->wep.key[i], mssid->wep.len[i]))
|
||||
{
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
|
||||
"encryption for dynamic VLAN");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vlan_dynamic_add(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan)
|
||||
{
|
||||
while (vlan) {
|
||||
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
|
||||
if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
|
||||
if (errno != EEXIST) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could "
|
||||
"not add VLAN %s: %s",
|
||||
vlan->ifname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
ifconfig_up(vlan->ifname);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
}
|
||||
|
||||
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_vlan_if_remove(hapd, vlan->ifname)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
|
||||
"iface: %s: %s",
|
||||
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)
|
||||
{
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
|
||||
return -1;
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
|
||||
__func__, vlan_id, vlan->ifname);
|
||||
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_vlan_if_add(hapd, n->ifname)) {
|
||||
os_free(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n->next = hapd->conf->vlan;
|
||||
hapd->conf->vlan = n;
|
||||
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
ifconfig_up(n->ifname);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
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;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
|
||||
|
||||
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_vlan_if_remove(hapd, vlan->ifname);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
* 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 "common/defs.h"
|
||||
#include "common/eapol_common.h"
|
||||
#include "common/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
|
||||
|
||||
#define FT_R0KH_R1KH_PULL_DATA_LEN 44
|
||||
#define FT_R0KH_R1KH_RESP_DATA_LEN 76
|
||||
#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
|
||||
|
||||
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];
|
||||
le16 pairwise;
|
||||
u8 pad[2]; /* 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 (88) */
|
||||
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];
|
||||
le16 pairwise;
|
||||
u8 pad[6]; /* 8-octet boundary for AES key wrap */
|
||||
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 wmm_enabled;
|
||||
int wmm_uapsd;
|
||||
int okc;
|
||||
int tx_status;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum mfp_options 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;
|
||||
int ft_over_ds;
|
||||
#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, enum wpa_alg 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 (*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);
|
||||
int 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);
|
||||
int 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);
|
||||
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int ack);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
size_t max_len, int auth_alg,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
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 */
|
File diff suppressed because it is too large
Load diff
|
@ -1,571 +0,0 @@
|
|||
/*
|
||||
* hostapd / WPA authenticator glue code
|
||||
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_1x.h"
|
||||
#include "preauth_auth.h"
|
||||
#include "sta_info.h"
|
||||
#include "tkip_countermeasures.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "wpa_auth.h"
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
struct wpa_auth_config *wconf)
|
||||
{
|
||||
wconf->wpa = conf->wpa;
|
||||
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
|
||||
wconf->wpa_pairwise = conf->wpa_pairwise;
|
||||
wconf->wpa_group = conf->wpa_group;
|
||||
wconf->wpa_group_rekey = conf->wpa_group_rekey;
|
||||
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
|
||||
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
|
||||
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
|
||||
wconf->rsn_pairwise = conf->rsn_pairwise;
|
||||
wconf->rsn_preauth = conf->rsn_preauth;
|
||||
wconf->eapol_version = conf->eapol_version;
|
||||
wconf->peerkey = conf->peerkey;
|
||||
wconf->wmm_enabled = conf->wmm_enabled;
|
||||
wconf->wmm_uapsd = conf->wmm_uapsd;
|
||||
wconf->okc = conf->okc;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
wconf->ieee80211w = conf->ieee80211w;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
wconf->ssid_len = conf->ssid.ssid_len;
|
||||
if (wconf->ssid_len > SSID_LEN)
|
||||
wconf->ssid_len = SSID_LEN;
|
||||
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
|
||||
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
|
||||
MOBILITY_DOMAIN_ID_LEN);
|
||||
if (conf->nas_identifier &&
|
||||
os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
|
||||
wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
|
||||
os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
|
||||
wconf->r0_key_holder_len);
|
||||
}
|
||||
os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
|
||||
wconf->r0_key_lifetime = conf->r0_key_lifetime;
|
||||
wconf->reassociation_deadline = conf->reassociation_deadline;
|
||||
wconf->r0kh_list = conf->r0kh_list;
|
||||
wconf->r1kh_list = conf->r1kh_list;
|
||||
wconf->pmk_r1_push = conf->pmk_r1_push;
|
||||
wconf->ft_over_ds = conf->ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
|
||||
logger_level level, const char *txt)
|
||||
{
|
||||
#ifndef CONFIG_NO_HOSTAPD_LOGGER
|
||||
struct hostapd_data *hapd = ctx;
|
||||
int hlevel;
|
||||
|
||||
switch (level) {
|
||||
case LOGGER_WARNING:
|
||||
hlevel = HOSTAPD_LEVEL_WARNING;
|
||||
break;
|
||||
case LOGGER_INFO:
|
||||
hlevel = HOSTAPD_LEVEL_INFO;
|
||||
break;
|
||||
case LOGGER_DEBUG:
|
||||
default:
|
||||
hlevel = HOSTAPD_LEVEL_DEBUG;
|
||||
break;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
|
||||
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
|
||||
u16 reason)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
|
||||
"STA " MACSTR " reason %d",
|
||||
__func__, MAC2STR(addr), reason);
|
||||
ap_sta_disconnect(hapd, NULL, addr, reason);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
michael_mic_failure(hapd, addr, 0);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
|
||||
wpa_eapol_variable var, int value)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL)
|
||||
return;
|
||||
switch (var) {
|
||||
case WPA_EAPOL_portEnabled:
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
|
||||
break;
|
||||
case WPA_EAPOL_portValid:
|
||||
ieee802_1x_notify_port_valid(sta->eapol_sm, value);
|
||||
break;
|
||||
case WPA_EAPOL_authorized:
|
||||
ieee802_1x_set_sta_authorized(hapd, sta, value);
|
||||
break;
|
||||
case WPA_EAPOL_portControl_Auto:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->portControl = Auto;
|
||||
break;
|
||||
case WPA_EAPOL_keyRun:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->keyRun = value ? TRUE : FALSE;
|
||||
break;
|
||||
case WPA_EAPOL_keyAvailable:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable =
|
||||
value ? TRUE : FALSE;
|
||||
break;
|
||||
case WPA_EAPOL_keyDone:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->keyDone = value ? TRUE : FALSE;
|
||||
break;
|
||||
case WPA_EAPOL_inc_EapolFramesTx:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->dot1xAuthEapolFramesTx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
|
||||
wpa_eapol_variable var)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL || sta->eapol_sm == NULL)
|
||||
return -1;
|
||||
switch (var) {
|
||||
case WPA_EAPOL_keyRun:
|
||||
return sta->eapol_sm->keyRun;
|
||||
case WPA_EAPOL_keyAvailable:
|
||||
return sta->eapol_sm->eap_if->eapKeyAvailable;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
const u8 *prev_psk)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
return hostapd_get_psk(hapd->conf, addr, prev_psk);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
|
||||
size_t *len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
const u8 *key;
|
||||
size_t keylen;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta == NULL)
|
||||
return -1;
|
||||
|
||||
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
|
||||
if (key == NULL)
|
||||
return -1;
|
||||
|
||||
if (keylen > *len)
|
||||
keylen = *len;
|
||||
os_memcpy(msk, key, keylen);
|
||||
*len = keylen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
|
||||
const u8 *addr, int idx, u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
const char *ifname = hapd->conf->iface;
|
||||
|
||||
if (vlan_id > 0) {
|
||||
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
|
||||
if (ifname == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
|
||||
key, key_len);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
|
||||
u8 *seq)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
|
||||
const u8 *data, size_t data_len,
|
||||
int encrypt)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
u32 flags = 0;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
flags = hostapd_sta_flags_to_drv(sta->flags);
|
||||
|
||||
return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
|
||||
encrypt, flags);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_for_each_sta(
|
||||
void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
|
||||
void *cb_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpa_auth_iface_iter_data {
|
||||
int (*cb)(struct wpa_authenticator *sm, void *ctx);
|
||||
void *cb_ctx;
|
||||
};
|
||||
|
||||
static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct wpa_auth_iface_iter_data *data = ctx;
|
||||
size_t i;
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
if (iface->bss[i]->wpa_auth &&
|
||||
data->cb(iface->bss[i]->wpa_auth, data->cb_ctx))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_for_each_auth(
|
||||
void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
|
||||
void *cb_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct wpa_auth_iface_iter_data data;
|
||||
if (hapd->iface->for_each_interface == NULL)
|
||||
return -1;
|
||||
data.cb = cb;
|
||||
data.cb_ctx = cb_ctx;
|
||||
return hapd->iface->for_each_interface(hapd->iface->interfaces,
|
||||
wpa_auth_iface_iter, &data);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
|
||||
struct wpa_auth_ft_iface_iter_data {
|
||||
struct hostapd_data *src_hapd;
|
||||
const u8 *dst;
|
||||
const u8 *data;
|
||||
size_t data_len;
|
||||
};
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct wpa_auth_ft_iface_iter_data *idata = ctx;
|
||||
struct hostapd_data *hapd;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hapd = iface->bss[j];
|
||||
if (hapd == idata->src_hapd)
|
||||
continue;
|
||||
if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
|
||||
"locally managed BSS " MACSTR "@%s -> "
|
||||
MACSTR "@%s",
|
||||
MAC2STR(idata->src_hapd->own_addr),
|
||||
idata->src_hapd->conf->iface,
|
||||
MAC2STR(hapd->own_addr), hapd->conf->iface);
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth,
|
||||
idata->src_hapd->own_addr,
|
||||
idata->data, idata->data_len);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct l2_ethhdr *buf;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
|
||||
int res;
|
||||
struct wpa_auth_ft_iface_iter_data idata;
|
||||
idata.src_hapd = hapd;
|
||||
idata.dst = dst;
|
||||
idata.data = data;
|
||||
idata.data_len = data_len;
|
||||
res = hapd->iface->for_each_interface(hapd->iface->interfaces,
|
||||
hostapd_wpa_auth_ft_iter,
|
||||
&idata);
|
||||
if (res == 1)
|
||||
return data_len;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
if (hapd->driver && hapd->driver->send_ether)
|
||||
return hapd->driver->send_ether(hapd->drv_priv, dst,
|
||||
hapd->own_addr, proto,
|
||||
data, data_len);
|
||||
if (hapd->l2 == NULL)
|
||||
return -1;
|
||||
|
||||
buf = os_malloc(sizeof(*buf) + data_len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
os_memcpy(buf->h_dest, dst, ETH_ALEN);
|
||||
os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
|
||||
buf->h_proto = host_to_be16(proto);
|
||||
os_memcpy(buf + 1, data, data_len);
|
||||
ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
|
||||
sizeof(*buf) + data_len);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
|
||||
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
int res;
|
||||
struct ieee80211_mgmt *m;
|
||||
size_t mlen;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (sta == NULL || sta->wpa_sm == NULL)
|
||||
return -1;
|
||||
|
||||
m = os_zalloc(sizeof(*m) + data_len);
|
||||
if (m == NULL)
|
||||
return -1;
|
||||
mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
|
||||
m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_ACTION);
|
||||
os_memcpy(m->da, dst, ETH_ALEN);
|
||||
os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(&m->u, data, data_len);
|
||||
|
||||
res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen);
|
||||
os_free(m);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_state_machine *
|
||||
hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_sta_add(hapd, sta_addr);
|
||||
if (sta == NULL)
|
||||
return NULL;
|
||||
if (sta->wpa_sm) {
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
return sta->wpa_sm;
|
||||
}
|
||||
|
||||
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
|
||||
if (sta->wpa_sm == NULL) {
|
||||
ap_free_sta(hapd, sta);
|
||||
return NULL;
|
||||
}
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
|
||||
return sta->wpa_sm;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct l2_ethhdr *ethhdr;
|
||||
if (len < sizeof(*ethhdr))
|
||||
return;
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
|
||||
len - sizeof(*ethhdr));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpa_auth_config _conf;
|
||||
struct wpa_auth_callbacks cb;
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
|
||||
hostapd_wpa_auth_conf(hapd->conf, &_conf);
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
|
||||
_conf.tx_status = 1;
|
||||
os_memset(&cb, 0, sizeof(cb));
|
||||
cb.ctx = hapd;
|
||||
cb.logger = hostapd_wpa_auth_logger;
|
||||
cb.disconnect = hostapd_wpa_auth_disconnect;
|
||||
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
|
||||
cb.set_eapol = hostapd_wpa_auth_set_eapol;
|
||||
cb.get_eapol = hostapd_wpa_auth_get_eapol;
|
||||
cb.get_psk = hostapd_wpa_auth_get_psk;
|
||||
cb.get_msk = hostapd_wpa_auth_get_msk;
|
||||
cb.set_key = hostapd_wpa_auth_set_key;
|
||||
cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
|
||||
cb.send_eapol = hostapd_wpa_auth_send_eapol;
|
||||
cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
|
||||
cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
|
||||
cb.send_ether = hostapd_wpa_auth_send_ether;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
|
||||
cb.add_sta = hostapd_wpa_auth_add_sta;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
|
||||
if (hapd->wpa_auth == NULL) {
|
||||
wpa_printf(MSG_ERROR, "WPA initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_set_privacy(hapd, 1)) {
|
||||
wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
|
||||
"for interface %s", hapd->conf->iface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
|
||||
if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
|
||||
"the kernel driver.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rsn_preauth_iface_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR, "Initialization of RSN "
|
||||
"pre-authentication failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (!hostapd_drv_none(hapd)) {
|
||||
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
|
||||
hapd->conf->bridge :
|
||||
hapd->conf->iface, NULL, ETH_P_RRB,
|
||||
hostapd_rrb_receive, hapd, 1);
|
||||
if (hapd->l2 == NULL &&
|
||||
(hapd->driver == NULL ||
|
||||
hapd->driver->send_ether == NULL)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
|
||||
"interface");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hostapd_reconfig_wpa(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpa_auth_config wpa_auth_conf;
|
||||
hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
|
||||
wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_deinit_wpa(struct hostapd_data *hapd)
|
||||
{
|
||||
rsn_preauth_iface_deinit(hapd);
|
||||
if (hapd->wpa_auth) {
|
||||
wpa_deinit(hapd->wpa_auth);
|
||||
hapd->wpa_auth = NULL;
|
||||
|
||||
if (hostapd_set_privacy(hapd, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not disable "
|
||||
"PrivacyInvoked for interface %s",
|
||||
hapd->conf->iface);
|
||||
}
|
||||
|
||||
if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove generic "
|
||||
"information element from interface %s",
|
||||
hapd->conf->iface);
|
||||
}
|
||||
}
|
||||
ieee802_1x_deinit(hapd);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
l2_packet_deinit(hapd->l2);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* EAPOL definitions shared between hostapd and wpa_supplicant
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAPOL_COMMON_H
|
||||
#define EAPOL_COMMON_H
|
||||
|
||||
/* IEEE Std 802.1X-2004 */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
struct ieee802_1x_hdr {
|
||||
u8 version;
|
||||
u8 type;
|
||||
be16 length;
|
||||
/* followed by length octets of data */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define EAPOL_VERSION 2
|
||||
|
||||
enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
|
||||
IEEE802_1X_TYPE_EAPOL_START = 1,
|
||||
IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
|
||||
IEEE802_1X_TYPE_EAPOL_KEY = 3,
|
||||
IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
|
||||
};
|
||||
|
||||
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
|
||||
EAPOL_KEY_TYPE_WPA = 254 };
|
||||
|
||||
#endif /* EAPOL_COMMON_H */
|
|
@ -1,347 +0,0 @@
|
|||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "ieee802_11_common.h"
|
||||
|
||||
|
||||
static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors)
|
||||
{
|
||||
unsigned int oui;
|
||||
|
||||
/* first 3 bytes in vendor specific information element are the IEEE
|
||||
* OUI of the vendor. The following byte is used a vendor specific
|
||||
* sub-type. */
|
||||
if (elen < 4) {
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_MSGDUMP, "short vendor specific "
|
||||
"information element ignored (len=%lu)",
|
||||
(unsigned long) elen);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
oui = WPA_GET_BE24(pos);
|
||||
switch (oui) {
|
||||
case OUI_MICROSOFT:
|
||||
/* Microsoft/Wi-Fi information elements are further typed and
|
||||
* subtyped */
|
||||
switch (pos[3]) {
|
||||
case 1:
|
||||
/* Microsoft OUI (00:50:F2) with OUI Type 1:
|
||||
* real WPA information element */
|
||||
elems->wpa_ie = pos;
|
||||
elems->wpa_ie_len = elen;
|
||||
break;
|
||||
case WMM_OUI_TYPE:
|
||||
/* WMM information element */
|
||||
if (elen < 5) {
|
||||
wpa_printf(MSG_MSGDUMP, "short WMM "
|
||||
"information element ignored "
|
||||
"(len=%lu)",
|
||||
(unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
switch (pos[4]) {
|
||||
case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
|
||||
case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
|
||||
/*
|
||||
* Share same pointer since only one of these
|
||||
* is used and they start with same data.
|
||||
* Length field can be used to distinguish the
|
||||
* IEs.
|
||||
*/
|
||||
elems->wmm = pos;
|
||||
elems->wmm_len = elen;
|
||||
break;
|
||||
case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
|
||||
elems->wmm_tspec = pos;
|
||||
elems->wmm_tspec_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE, "unknown WMM "
|
||||
"information element ignored "
|
||||
"(subtype=%d len=%lu)",
|
||||
pos[4], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* Wi-Fi Protected Setup (WPS) IE */
|
||||
elems->wps_ie = pos;
|
||||
elems->wps_ie_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
|
||||
"information element ignored "
|
||||
"(type=%d len=%lu)",
|
||||
pos[3], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case OUI_WFA:
|
||||
switch (pos[3]) {
|
||||
case P2P_OUI_TYPE:
|
||||
/* Wi-Fi Alliance - P2P IE */
|
||||
elems->p2p = pos;
|
||||
elems->p2p_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
|
||||
"information element ignored "
|
||||
"(type=%d len=%lu)\n",
|
||||
pos[3], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case OUI_BROADCOM:
|
||||
switch (pos[3]) {
|
||||
case VENDOR_HT_CAPAB_OUI_TYPE:
|
||||
elems->vendor_ht_cap = pos;
|
||||
elems->vendor_ht_cap_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
|
||||
"information element ignored "
|
||||
"(type=%d len=%lu)",
|
||||
pos[3], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
|
||||
"information element ignored (vendor OUI "
|
||||
"%02x:%02x:%02x len=%lu)",
|
||||
pos[0], pos[1], pos[2], (unsigned long) elen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_11_parse_elems - Parse information elements in management frames
|
||||
* @start: Pointer to the start of IEs
|
||||
* @len: Length of IE buffer in octets
|
||||
* @elems: Data structure for parsed elements
|
||||
* @show_errors: Whether to show parsing errors in debug log
|
||||
* Returns: Parsing result
|
||||
*/
|
||||
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors)
|
||||
{
|
||||
size_t left = len;
|
||||
const u8 *pos = start;
|
||||
int unknown = 0;
|
||||
|
||||
os_memset(elems, 0, sizeof(*elems));
|
||||
|
||||
while (left >= 2) {
|
||||
u8 id, elen;
|
||||
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
left -= 2;
|
||||
|
||||
if (elen > left) {
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
|
||||
"parse failed (id=%d elen=%d "
|
||||
"left=%lu)",
|
||||
id, elen, (unsigned long) left);
|
||||
wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
|
||||
}
|
||||
return ParseFailed;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case WLAN_EID_SSID:
|
||||
elems->ssid = pos;
|
||||
elems->ssid_len = elen;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
elems->supp_rates = pos;
|
||||
elems->supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FH_PARAMS:
|
||||
elems->fh_params = pos;
|
||||
elems->fh_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_DS_PARAMS:
|
||||
elems->ds_params = pos;
|
||||
elems->ds_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CF_PARAMS:
|
||||
elems->cf_params = pos;
|
||||
elems->cf_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIM:
|
||||
elems->tim = pos;
|
||||
elems->tim_len = elen;
|
||||
break;
|
||||
case WLAN_EID_IBSS_PARAMS:
|
||||
elems->ibss_params = pos;
|
||||
elems->ibss_params_len = elen;
|
||||
break;
|
||||
case WLAN_EID_CHALLENGE:
|
||||
elems->challenge = pos;
|
||||
elems->challenge_len = elen;
|
||||
break;
|
||||
case WLAN_EID_ERP_INFO:
|
||||
elems->erp_info = pos;
|
||||
elems->erp_info_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
elems->ext_supp_rates = pos;
|
||||
elems->ext_supp_rates_len = elen;
|
||||
break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (ieee802_11_parse_vendor_specific(pos, elen,
|
||||
elems,
|
||||
show_errors))
|
||||
unknown++;
|
||||
break;
|
||||
case WLAN_EID_RSN:
|
||||
elems->rsn_ie = pos;
|
||||
elems->rsn_ie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_PWR_CAPABILITY:
|
||||
elems->power_cap = pos;
|
||||
elems->power_cap_len = elen;
|
||||
break;
|
||||
case WLAN_EID_SUPPORTED_CHANNELS:
|
||||
elems->supp_channels = pos;
|
||||
elems->supp_channels_len = elen;
|
||||
break;
|
||||
case WLAN_EID_MOBILITY_DOMAIN:
|
||||
elems->mdie = pos;
|
||||
elems->mdie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_FAST_BSS_TRANSITION:
|
||||
elems->ftie = pos;
|
||||
elems->ftie_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TIMEOUT_INTERVAL:
|
||||
elems->timeout_int = pos;
|
||||
elems->timeout_int_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_CAP:
|
||||
elems->ht_capabilities = pos;
|
||||
elems->ht_capabilities_len = elen;
|
||||
break;
|
||||
case WLAN_EID_HT_OPERATION:
|
||||
elems->ht_operation = pos;
|
||||
elems->ht_operation_len = elen;
|
||||
break;
|
||||
case WLAN_EID_LINK_ID:
|
||||
if (elen < 18)
|
||||
break;
|
||||
elems->link_id = pos;
|
||||
break;
|
||||
default:
|
||||
unknown++;
|
||||
if (!show_errors)
|
||||
break;
|
||||
wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
|
||||
"ignored unknown element (id=%d elen=%d)",
|
||||
id, elen);
|
||||
break;
|
||||
}
|
||||
|
||||
left -= elen;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
if (left)
|
||||
return ParseFailed;
|
||||
|
||||
return unknown ? ParseUnknown : ParseOK;
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
|
||||
{
|
||||
int count = 0;
|
||||
const u8 *pos, *end;
|
||||
|
||||
if (ies == NULL)
|
||||
return 0;
|
||||
|
||||
pos = ies;
|
||||
end = ies + ies_len;
|
||||
|
||||
while (pos + 2 <= end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
break;
|
||||
count++;
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
u32 oui_type)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
const u8 *end, *pos, *ie;
|
||||
|
||||
pos = ies;
|
||||
end = ies + ies_len;
|
||||
ie = NULL;
|
||||
|
||||
while (pos + 1 < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
return NULL;
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||
WPA_GET_BE32(&pos[2]) == oui_type) {
|
||||
ie = pos;
|
||||
break;
|
||||
}
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
if (ie == NULL)
|
||||
return NULL; /* No specified vendor IE found */
|
||||
|
||||
buf = wpabuf_alloc(ies_len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* There may be multiple vendor IEs in the message, so need to
|
||||
* concatenate their 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]) == oui_type)
|
||||
wpabuf_put_data(buf, pos + 6, pos[1] - 4);
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* IEEE 802.11 Common routines
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_COMMON_H
|
||||
#define IEEE802_11_COMMON_H
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
const u8 *ssid;
|
||||
const u8 *supp_rates;
|
||||
const u8 *fh_params;
|
||||
const u8 *ds_params;
|
||||
const u8 *cf_params;
|
||||
const u8 *tim;
|
||||
const u8 *ibss_params;
|
||||
const u8 *challenge;
|
||||
const u8 *erp_info;
|
||||
const u8 *ext_supp_rates;
|
||||
const u8 *wpa_ie;
|
||||
const u8 *rsn_ie;
|
||||
const u8 *wmm; /* WMM Information or Parameter Element */
|
||||
const u8 *wmm_tspec;
|
||||
const u8 *wps_ie;
|
||||
const u8 *power_cap;
|
||||
const u8 *supp_channels;
|
||||
const u8 *mdie;
|
||||
const u8 *ftie;
|
||||
const u8 *timeout_int;
|
||||
const u8 *ht_capabilities;
|
||||
const u8 *ht_operation;
|
||||
const u8 *vendor_ht_cap;
|
||||
const u8 *p2p;
|
||||
const u8 *link_id;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
u8 fh_params_len;
|
||||
u8 ds_params_len;
|
||||
u8 cf_params_len;
|
||||
u8 tim_len;
|
||||
u8 ibss_params_len;
|
||||
u8 challenge_len;
|
||||
u8 erp_info_len;
|
||||
u8 ext_supp_rates_len;
|
||||
u8 wpa_ie_len;
|
||||
u8 rsn_ie_len;
|
||||
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
|
||||
u8 wmm_tspec_len;
|
||||
u8 wps_ie_len;
|
||||
u8 power_cap_len;
|
||||
u8 supp_channels_len;
|
||||
u8 mdie_len;
|
||||
u8 ftie_len;
|
||||
u8 timeout_int_len;
|
||||
u8 ht_capabilities_len;
|
||||
u8 ht_operation_len;
|
||||
u8 vendor_ht_cap_len;
|
||||
u8 p2p_len;
|
||||
};
|
||||
|
||||
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
||||
|
||||
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
struct ieee802_11_elems *elems,
|
||||
int show_errors);
|
||||
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
|
||||
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
u32 oui_type);
|
||||
|
||||
#endif /* IEEE802_11_COMMON_H */
|
|
@ -1,800 +0,0 @@
|
|||
/*
|
||||
* IEEE 802.11 Frame type definitions
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE802_11_DEFS_H
|
||||
#define IEEE802_11_DEFS_H
|
||||
|
||||
/* IEEE 802.11 defines */
|
||||
|
||||
#define WLAN_FC_PVER 0x0003
|
||||
#define WLAN_FC_TODS 0x0100
|
||||
#define WLAN_FC_FROMDS 0x0200
|
||||
#define WLAN_FC_MOREFRAG 0x0400
|
||||
#define WLAN_FC_RETRY 0x0800
|
||||
#define WLAN_FC_PWRMGT 0x1000
|
||||
#define WLAN_FC_MOREDATA 0x2000
|
||||
#define WLAN_FC_ISWEP 0x4000
|
||||
#define WLAN_FC_ORDER 0x8000
|
||||
|
||||
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
|
||||
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
|
||||
|
||||
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
|
||||
#define WLAN_GET_SEQ_SEQ(seq) \
|
||||
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
|
||||
|
||||
#define WLAN_FC_TYPE_MGMT 0
|
||||
#define WLAN_FC_TYPE_CTRL 1
|
||||
#define WLAN_FC_TYPE_DATA 2
|
||||
|
||||
/* management */
|
||||
#define WLAN_FC_STYPE_ASSOC_REQ 0
|
||||
#define WLAN_FC_STYPE_ASSOC_RESP 1
|
||||
#define WLAN_FC_STYPE_REASSOC_REQ 2
|
||||
#define WLAN_FC_STYPE_REASSOC_RESP 3
|
||||
#define WLAN_FC_STYPE_PROBE_REQ 4
|
||||
#define WLAN_FC_STYPE_PROBE_RESP 5
|
||||
#define WLAN_FC_STYPE_BEACON 8
|
||||
#define WLAN_FC_STYPE_ATIM 9
|
||||
#define WLAN_FC_STYPE_DISASSOC 10
|
||||
#define WLAN_FC_STYPE_AUTH 11
|
||||
#define WLAN_FC_STYPE_DEAUTH 12
|
||||
#define WLAN_FC_STYPE_ACTION 13
|
||||
|
||||
/* control */
|
||||
#define WLAN_FC_STYPE_PSPOLL 10
|
||||
#define WLAN_FC_STYPE_RTS 11
|
||||
#define WLAN_FC_STYPE_CTS 12
|
||||
#define WLAN_FC_STYPE_ACK 13
|
||||
#define WLAN_FC_STYPE_CFEND 14
|
||||
#define WLAN_FC_STYPE_CFENDACK 15
|
||||
|
||||
/* data */
|
||||
#define WLAN_FC_STYPE_DATA 0
|
||||
#define WLAN_FC_STYPE_DATA_CFACK 1
|
||||
#define WLAN_FC_STYPE_DATA_CFPOLL 2
|
||||
#define WLAN_FC_STYPE_DATA_CFACKPOLL 3
|
||||
#define WLAN_FC_STYPE_NULLFUNC 4
|
||||
#define WLAN_FC_STYPE_CFACK 5
|
||||
#define WLAN_FC_STYPE_CFPOLL 6
|
||||
#define WLAN_FC_STYPE_CFACKPOLL 7
|
||||
#define WLAN_FC_STYPE_QOS_DATA 8
|
||||
#define WLAN_FC_STYPE_QOS_DATA_CFACK 9
|
||||
#define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10
|
||||
#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11
|
||||
#define WLAN_FC_STYPE_QOS_NULL 12
|
||||
#define WLAN_FC_STYPE_QOS_CFPOLL 14
|
||||
#define WLAN_FC_STYPE_QOS_CFACKPOLL 15
|
||||
|
||||
/* Authentication algorithms */
|
||||
#define WLAN_AUTH_OPEN 0
|
||||
#define WLAN_AUTH_SHARED_KEY 1
|
||||
#define WLAN_AUTH_FT 2
|
||||
#define WLAN_AUTH_LEAP 128
|
||||
|
||||
#define WLAN_AUTH_CHALLENGE_LEN 128
|
||||
|
||||
#define WLAN_CAPABILITY_ESS BIT(0)
|
||||
#define WLAN_CAPABILITY_IBSS BIT(1)
|
||||
#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
|
||||
#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
|
||||
#define WLAN_CAPABILITY_PRIVACY BIT(4)
|
||||
#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
|
||||
#define WLAN_CAPABILITY_PBCC BIT(6)
|
||||
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
|
||||
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
|
||||
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
|
||||
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
|
||||
|
||||
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
|
||||
#define WLAN_STATUS_SUCCESS 0
|
||||
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
|
||||
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
|
||||
#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
|
||||
#define WLAN_STATUS_SECURITY_DISABLED 5
|
||||
#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
|
||||
#define WLAN_STATUS_NOT_IN_SAME_BSS 7
|
||||
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
|
||||
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
|
||||
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
|
||||
#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
|
||||
#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
|
||||
#define WLAN_STATUS_CHALLENGE_FAIL 15
|
||||
#define WLAN_STATUS_AUTH_TIMEOUT 16
|
||||
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
|
||||
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
|
||||
/* IEEE 802.11b */
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
|
||||
/* IEEE 802.11h */
|
||||
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
|
||||
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
|
||||
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
|
||||
/* IEEE 802.11g */
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
|
||||
#define WLAN_STATUS_R0KH_UNREACHABLE 28
|
||||
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
|
||||
/* IEEE 802.11w */
|
||||
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
|
||||
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
|
||||
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
|
||||
#define WLAN_STATUS_REQUEST_DECLINED 37
|
||||
#define WLAN_STATUS_INVALID_PARAMETERS 38
|
||||
/* IEEE 802.11i */
|
||||
#define WLAN_STATUS_INVALID_IE 40
|
||||
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
|
||||
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
|
||||
#define WLAN_STATUS_AKMP_NOT_VALID 43
|
||||
#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
|
||||
#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
|
||||
#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
|
||||
#define WLAN_STATUS_TS_NOT_CREATED 47
|
||||
#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
|
||||
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
|
||||
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
|
||||
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
|
||||
/* IEEE 802.11r */
|
||||
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
|
||||
#define WLAN_STATUS_INVALID_PMKID 53
|
||||
#define WLAN_STATUS_INVALID_MDIE 54
|
||||
#define WLAN_STATUS_INVALID_FTIE 55
|
||||
#define WLAN_STATUS_INVALID_RSNIE 72
|
||||
|
||||
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
|
||||
#define WLAN_REASON_UNSPECIFIED 1
|
||||
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
|
||||
#define WLAN_REASON_DEAUTH_LEAVING 3
|
||||
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
|
||||
#define WLAN_REASON_DISASSOC_AP_BUSY 5
|
||||
#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
|
||||
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
|
||||
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
|
||||
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
|
||||
/* IEEE 802.11h */
|
||||
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
|
||||
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
|
||||
/* IEEE 802.11i */
|
||||
#define WLAN_REASON_INVALID_IE 13
|
||||
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
|
||||
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
|
||||
#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
|
||||
#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
|
||||
#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
|
||||
#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
|
||||
#define WLAN_REASON_AKMP_NOT_VALID 20
|
||||
#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
|
||||
#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
|
||||
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
|
||||
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
|
||||
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
|
||||
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
|
||||
/* IEEE 802.11e */
|
||||
#define WLAN_REASON_DISASSOC_LOW_ACK 34
|
||||
|
||||
|
||||
/* Information Element IDs */
|
||||
#define WLAN_EID_SSID 0
|
||||
#define WLAN_EID_SUPP_RATES 1
|
||||
#define WLAN_EID_FH_PARAMS 2
|
||||
#define WLAN_EID_DS_PARAMS 3
|
||||
#define WLAN_EID_CF_PARAMS 4
|
||||
#define WLAN_EID_TIM 5
|
||||
#define WLAN_EID_IBSS_PARAMS 6
|
||||
#define WLAN_EID_COUNTRY 7
|
||||
#define WLAN_EID_CHALLENGE 16
|
||||
/* EIDs defined by IEEE 802.11h - START */
|
||||
#define WLAN_EID_PWR_CONSTRAINT 32
|
||||
#define WLAN_EID_PWR_CAPABILITY 33
|
||||
#define WLAN_EID_TPC_REQUEST 34
|
||||
#define WLAN_EID_TPC_REPORT 35
|
||||
#define WLAN_EID_SUPPORTED_CHANNELS 36
|
||||
#define WLAN_EID_CHANNEL_SWITCH 37
|
||||
#define WLAN_EID_MEASURE_REQUEST 38
|
||||
#define WLAN_EID_MEASURE_REPORT 39
|
||||
#define WLAN_EID_QUITE 40
|
||||
#define WLAN_EID_IBSS_DFS 41
|
||||
/* EIDs defined by IEEE 802.11h - END */
|
||||
#define WLAN_EID_ERP_INFO 42
|
||||
#define WLAN_EID_HT_CAP 45
|
||||
#define WLAN_EID_RSN 48
|
||||
#define WLAN_EID_EXT_SUPP_RATES 50
|
||||
#define WLAN_EID_MOBILITY_DOMAIN 54
|
||||
#define WLAN_EID_FAST_BSS_TRANSITION 55
|
||||
#define WLAN_EID_TIMEOUT_INTERVAL 56
|
||||
#define WLAN_EID_RIC_DATA 57
|
||||
#define WLAN_EID_HT_OPERATION 61
|
||||
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
|
||||
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
|
||||
#define WLAN_EID_20_40_BSS_INTOLERANT 73
|
||||
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
|
||||
#define WLAN_EID_MMIE 76
|
||||
#define WLAN_EID_LINK_ID 101
|
||||
#define WLAN_EID_ADV_PROTO 108
|
||||
#define WLAN_EID_EXT_CAPAB 127
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
|
||||
|
||||
/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
|
||||
#define WLAN_ACTION_SPECTRUM_MGMT 0
|
||||
#define WLAN_ACTION_QOS 1
|
||||
#define WLAN_ACTION_DLS 2
|
||||
#define WLAN_ACTION_BLOCK_ACK 3
|
||||
#define WLAN_ACTION_PUBLIC 4
|
||||
#define WLAN_ACTION_RADIO_MEASUREMENT 5
|
||||
#define WLAN_ACTION_FT 6
|
||||
#define WLAN_ACTION_HT 7
|
||||
#define WLAN_ACTION_SA_QUERY 8
|
||||
#define WLAN_ACTION_TDLS 12
|
||||
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
|
||||
#define WLAN_ACTION_VENDOR_SPECIFIC 127
|
||||
|
||||
/* Public action codes */
|
||||
#define WLAN_PA_VENDOR_SPECIFIC 9
|
||||
#define WLAN_PA_GAS_INITIAL_REQ 10
|
||||
#define WLAN_PA_GAS_INITIAL_RESP 11
|
||||
#define WLAN_PA_GAS_COMEBACK_REQ 12
|
||||
#define WLAN_PA_GAS_COMEBACK_RESP 13
|
||||
|
||||
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
|
||||
#define WLAN_SA_QUERY_REQUEST 0
|
||||
#define WLAN_SA_QUERY_RESPONSE 1
|
||||
|
||||
#define WLAN_SA_QUERY_TR_ID_LEN 2
|
||||
|
||||
/* TDLS action codes */
|
||||
#define WLAN_TDLS_SETUP_REQUEST 0
|
||||
#define WLAN_TDLS_SETUP_RESPONSE 1
|
||||
#define WLAN_TDLS_SETUP_CONFIRM 2
|
||||
#define WLAN_TDLS_TEARDOWN 3
|
||||
#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
|
||||
#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
|
||||
#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
|
||||
#define WLAN_TDLS_PEER_PSM_REQUEST 7
|
||||
#define WLAN_TDLS_PEER_PSM_RESPONSE 8
|
||||
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
|
||||
#define WLAN_TDLS_DISCOVERY_REQUEST 10
|
||||
|
||||
/* Timeout Interval Type */
|
||||
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
|
||||
#define WLAN_TIMEOUT_KEY_LIFETIME 2
|
||||
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
|
||||
|
||||
/* Advertisement Protocol ID definitions (IEEE 802.11u) */
|
||||
enum adv_proto_id {
|
||||
NATIVE_QUERY_PROTOCOL = 0,
|
||||
MIH_INFO_SERVICE = 1,
|
||||
MIH_CMD_AND_EVENT_DISCOVERY = 2,
|
||||
EMERGENCY_ALERT_SYSTEM = 3,
|
||||
LOCATION_TO_SERVICE = 4,
|
||||
ADV_PROTO_VENDOR_SPECIFIC = 221
|
||||
};
|
||||
|
||||
/* Native Query Protocol info ID definitions (IEEE 802.11u) */
|
||||
enum nqp_info_id {
|
||||
NQP_CAPABILITY_LIST = 256,
|
||||
NQP_VENUE_NAME = 257,
|
||||
NQP_EMERGENCY_CALL_NUMBER = 258,
|
||||
NQP_NETWORK_AUTH_TYPE = 259,
|
||||
NQP_ROAMING_CONSORTIUM = 260,
|
||||
NQP_IP_ADDR_TYPE_AVAILABILITY = 261,
|
||||
NQP_NAI_REALM = 262,
|
||||
NQP_3GPP_CELLULAR_NETWORK = 263,
|
||||
NQP_AP_GEOSPATIAL_LOCATION = 264,
|
||||
NQP_AP_CIVIC_LOCATION = 265,
|
||||
NQP_DOMAIN_NAME = 266,
|
||||
NQP_EMERGENCY_ALERT_URI = 267,
|
||||
NQP_VENDOR_SPECIFIC = 56797
|
||||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
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;
|
||||
|
||||
#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))
|
||||
|
||||
struct ieee80211_mgmt {
|
||||
le16 frame_control;
|
||||
le16 duration;
|
||||
u8 da[6];
|
||||
u8 sa[6];
|
||||
u8 bssid[6];
|
||||
le16 seq_ctrl;
|
||||
union {
|
||||
struct {
|
||||
le16 auth_alg;
|
||||
le16 auth_transaction;
|
||||
le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED auth;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED deauth;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED assoc_req;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 status_code;
|
||||
le16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
u8 current_ap[6];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED reassoc_req;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED disassoc;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
le16 beacon_int;
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED beacon;
|
||||
struct {
|
||||
/* only variable items: SSID, Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED probe_req;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
le16 beacon_int;
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED probe_resp;
|
||||
struct {
|
||||
u8 category;
|
||||
union {
|
||||
struct {
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED wmm_action;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 element_id;
|
||||
u8 length;
|
||||
u8 switch_mode;
|
||||
u8 new_chan;
|
||||
u8 switch_count;
|
||||
} STRUCT_PACKED chan_switch;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
u8 variable[0]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_req;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
le16 status_code;
|
||||
u8 variable[0]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
} STRUCT_PACKED sa_query_req;
|
||||
struct {
|
||||
u8 action; /* */
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
} STRUCT_PACKED sa_query_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED public_action;
|
||||
struct {
|
||||
u8 action; /* 9 */
|
||||
u8 oui[3];
|
||||
/* Vendor-specific content */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED vs_public_action;
|
||||
} u;
|
||||
} STRUCT_PACKED action;
|
||||
} u;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
struct ieee80211_ht_capabilities {
|
||||
le16 ht_capabilities_info;
|
||||
u8 a_mpdu_params;
|
||||
u8 supported_mcs_set[16];
|
||||
le16 ht_extended_capabilities;
|
||||
le32 tx_bf_capability_info;
|
||||
u8 asel_capabilities;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
struct ieee80211_ht_operation {
|
||||
u8 control_chan;
|
||||
u8 ht_param;
|
||||
le16 operation_mode;
|
||||
le16 stbc_param;
|
||||
u8 basic_set[16];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define ERP_INFO_NON_ERP_PRESENT BIT(0)
|
||||
#define ERP_INFO_USE_PROTECTION BIT(1)
|
||||
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
|
||||
|
||||
|
||||
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
|
||||
#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1))
|
||||
#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3)))
|
||||
#define HT_CAP_INFO_SMPS_STATIC ((u16) 0)
|
||||
#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2))
|
||||
#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3)))
|
||||
#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4))
|
||||
#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5))
|
||||
#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6))
|
||||
#define HT_CAP_INFO_TX_STBC ((u16) BIT(7))
|
||||
#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9)))
|
||||
#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8))
|
||||
#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9))
|
||||
#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9)))
|
||||
#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10))
|
||||
#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11))
|
||||
#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12))
|
||||
#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13))
|
||||
#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14))
|
||||
#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15))
|
||||
|
||||
|
||||
#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0))
|
||||
#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1
|
||||
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8
|
||||
#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10))
|
||||
#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11))
|
||||
|
||||
|
||||
#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
|
||||
#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
|
||||
#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
|
||||
#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
|
||||
#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
|
||||
#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
|
||||
#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
|
||||
#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
|
||||
#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
|
||||
#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
|
||||
#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
|
||||
#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
|
||||
#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
|
||||
|
||||
|
||||
#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
|
||||
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
|
||||
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
|
||||
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
|
||||
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
|
||||
#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
|
||||
#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
|
||||
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
|
||||
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
|
||||
#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
|
||||
#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
|
||||
#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
|
||||
#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
|
||||
|
||||
|
||||
#define OP_MODE_PURE 0
|
||||
#define OP_MODE_MAY_BE_LEGACY_STAS 1
|
||||
#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
|
||||
#define OP_MODE_MIXED 3
|
||||
|
||||
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
|
||||
((le16) (0x0001 | 0x0002))
|
||||
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
|
||||
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
|
||||
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
|
||||
#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
|
||||
|
||||
#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
|
||||
#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
|
||||
#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8))
|
||||
#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
|
||||
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
|
||||
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
|
||||
|
||||
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
|
||||
|
||||
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
|
||||
* 00:50:F2 */
|
||||
#define WPA_IE_VENDOR_TYPE 0x0050f201
|
||||
#define WPS_IE_VENDOR_TYPE 0x0050f204
|
||||
#define OUI_WFA 0x506f9a
|
||||
#define P2P_IE_VENDOR_TYPE 0x506f9a09
|
||||
|
||||
#define WMM_OUI_TYPE 2
|
||||
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
|
||||
#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
|
||||
#define WMM_VERSION 1
|
||||
|
||||
#define WMM_ACTION_CODE_ADDTS_REQ 0
|
||||
#define WMM_ACTION_CODE_ADDTS_RESP 1
|
||||
#define WMM_ACTION_CODE_DELTS 2
|
||||
|
||||
#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
|
||||
#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
|
||||
/* 2 - Reserved */
|
||||
#define WMM_ADDTS_STATUS_REFUSED 3
|
||||
/* 4-255 - Reserved */
|
||||
|
||||
/* WMM TSPEC Direction Field Values */
|
||||
#define WMM_TSPEC_DIRECTION_UPLINK 0
|
||||
#define WMM_TSPEC_DIRECTION_DOWNLINK 1
|
||||
/* 2 - Reserved */
|
||||
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
|
||||
|
||||
/*
|
||||
* WMM Information Element (used in (Re)Association Request frames; may also be
|
||||
* used in Beacon frames)
|
||||
*/
|
||||
struct wmm_information_element {
|
||||
/* Element ID: 221 (0xdd); Length: 7 */
|
||||
/* required fields for WMM version 1 */
|
||||
u8 oui[3]; /* 00:50:f2 */
|
||||
u8 oui_type; /* 2 */
|
||||
u8 oui_subtype; /* 0 */
|
||||
u8 version; /* 1 for WMM version 1.0 */
|
||||
u8 qos_info; /* AP/STA specific QoS info */
|
||||
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define WMM_AC_AIFSN_MASK 0x0f
|
||||
#define WMM_AC_AIFNS_SHIFT 0
|
||||
#define WMM_AC_ACM 0x10
|
||||
#define WMM_AC_ACI_MASK 0x60
|
||||
#define WMM_AC_ACI_SHIFT 5
|
||||
|
||||
#define WMM_AC_ECWMIN_MASK 0x0f
|
||||
#define WMM_AC_ECWMIN_SHIFT 0
|
||||
#define WMM_AC_ECWMAX_MASK 0xf0
|
||||
#define WMM_AC_ECWMAX_SHIFT 4
|
||||
|
||||
struct wmm_ac_parameter {
|
||||
u8 aci_aifsn; /* AIFSN, ACM, ACI */
|
||||
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
|
||||
le16 txop_limit;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/*
|
||||
* WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
|
||||
* Response frmaes)
|
||||
*/
|
||||
struct wmm_parameter_element {
|
||||
/* Element ID: 221 (0xdd); Length: 24 */
|
||||
/* required fields for WMM version 1 */
|
||||
u8 oui[3]; /* 00:50:f2 */
|
||||
u8 oui_type; /* 2 */
|
||||
u8 oui_subtype; /* 1 */
|
||||
u8 version; /* 1 for WMM version 1.0 */
|
||||
u8 qos_info; /* AP/STA specif QoS info */
|
||||
u8 reserved; /* 0 */
|
||||
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
|
||||
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* WMM TSPEC Element */
|
||||
struct wmm_tspec_element {
|
||||
u8 eid; /* 221 = 0xdd */
|
||||
u8 length; /* 6 + 55 = 61 */
|
||||
u8 oui[3]; /* 00:50:f2 */
|
||||
u8 oui_type; /* 2 */
|
||||
u8 oui_subtype; /* 2 */
|
||||
u8 version; /* 1 */
|
||||
/* WMM TSPEC body (55 octets): */
|
||||
u8 ts_info[3];
|
||||
le16 nominal_msdu_size;
|
||||
le16 maximum_msdu_size;
|
||||
le32 minimum_service_interval;
|
||||
le32 maximum_service_interval;
|
||||
le32 inactivity_interval;
|
||||
le32 suspension_interval;
|
||||
le32 service_start_time;
|
||||
le32 minimum_data_rate;
|
||||
le32 mean_data_rate;
|
||||
le32 peak_data_rate;
|
||||
le32 maximum_burst_size;
|
||||
le32 delay_bound;
|
||||
le32 minimum_phy_rate;
|
||||
le16 surplus_bandwidth_allowance;
|
||||
le16 medium_time;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
/* Access Categories / ACI to AC coding */
|
||||
enum {
|
||||
WMM_AC_BE = 0 /* Best Effort */,
|
||||
WMM_AC_BK = 1 /* Background */,
|
||||
WMM_AC_VI = 2 /* Video */,
|
||||
WMM_AC_VO = 3 /* Voice */
|
||||
};
|
||||
|
||||
|
||||
/* Wi-Fi Direct (P2P) */
|
||||
|
||||
#define P2P_OUI_TYPE 9
|
||||
|
||||
enum p2p_attr_id {
|
||||
P2P_ATTR_STATUS = 0,
|
||||
P2P_ATTR_MINOR_REASON_CODE = 1,
|
||||
P2P_ATTR_CAPABILITY = 2,
|
||||
P2P_ATTR_DEVICE_ID = 3,
|
||||
P2P_ATTR_GROUP_OWNER_INTENT = 4,
|
||||
P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
|
||||
P2P_ATTR_LISTEN_CHANNEL = 6,
|
||||
P2P_ATTR_GROUP_BSSID = 7,
|
||||
P2P_ATTR_EXT_LISTEN_TIMING = 8,
|
||||
P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
|
||||
P2P_ATTR_MANAGEABILITY = 10,
|
||||
P2P_ATTR_CHANNEL_LIST = 11,
|
||||
P2P_ATTR_NOTICE_OF_ABSENCE = 12,
|
||||
P2P_ATTR_DEVICE_INFO = 13,
|
||||
P2P_ATTR_GROUP_INFO = 14,
|
||||
P2P_ATTR_GROUP_ID = 15,
|
||||
P2P_ATTR_INTERFACE = 16,
|
||||
P2P_ATTR_OPERATING_CHANNEL = 17,
|
||||
P2P_ATTR_INVITATION_FLAGS = 18,
|
||||
P2P_ATTR_VENDOR_SPECIFIC = 221
|
||||
};
|
||||
|
||||
#define P2P_MAX_GO_INTENT 15
|
||||
|
||||
/* P2P Capability - Device Capability bitmap */
|
||||
#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
|
||||
#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
|
||||
#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
|
||||
#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
|
||||
#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
|
||||
#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
|
||||
|
||||
/* P2P Capability - Group Capability bitmap */
|
||||
#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
|
||||
#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
|
||||
#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
|
||||
#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
|
||||
#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
|
||||
#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
|
||||
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
|
||||
|
||||
/* Invitation Flags */
|
||||
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
|
||||
|
||||
/* P2P Manageability */
|
||||
#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
|
||||
#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
|
||||
#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
|
||||
|
||||
enum p2p_status_code {
|
||||
P2P_SC_SUCCESS = 0,
|
||||
P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
|
||||
P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
|
||||
P2P_SC_FAIL_LIMIT_REACHED = 3,
|
||||
P2P_SC_FAIL_INVALID_PARAMS = 4,
|
||||
P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
|
||||
P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
|
||||
P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
|
||||
P2P_SC_FAIL_UNKNOWN_GROUP = 8,
|
||||
P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
|
||||
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
|
||||
P2P_SC_FAIL_REJECTED_BY_USER = 11,
|
||||
};
|
||||
|
||||
#define P2P_WILDCARD_SSID "DIRECT-"
|
||||
#define P2P_WILDCARD_SSID_LEN 7
|
||||
|
||||
/* P2P action frames */
|
||||
enum p2p_act_frame_type {
|
||||
P2P_NOA = 0,
|
||||
P2P_PRESENCE_REQ = 1,
|
||||
P2P_PRESENCE_RESP = 2,
|
||||
P2P_GO_DISC_REQ = 3
|
||||
};
|
||||
|
||||
/* P2P public action frames */
|
||||
enum p2p_action_frame_type {
|
||||
P2P_GO_NEG_REQ = 0,
|
||||
P2P_GO_NEG_RESP = 1,
|
||||
P2P_GO_NEG_CONF = 2,
|
||||
P2P_INVITATION_REQ = 3,
|
||||
P2P_INVITATION_RESP = 4,
|
||||
P2P_DEV_DISC_REQ = 5,
|
||||
P2P_DEV_DISC_RESP = 6,
|
||||
P2P_PROV_DISC_REQ = 7,
|
||||
P2P_PROV_DISC_RESP = 8
|
||||
};
|
||||
|
||||
enum p2p_service_protocol_type {
|
||||
P2P_SERV_ALL_SERVICES = 0,
|
||||
P2P_SERV_BONJOUR = 1,
|
||||
P2P_SERV_UPNP = 2,
|
||||
P2P_SERV_WS_DISCOVERY = 3,
|
||||
P2P_SERV_VENDOR_SPECIFIC = 255
|
||||
};
|
||||
|
||||
enum p2p_sd_status {
|
||||
P2P_SD_SUCCESS = 0,
|
||||
P2P_SD_PROTO_NOT_AVAILABLE = 1,
|
||||
P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
|
||||
P2P_SD_BAD_REQUEST = 3
|
||||
};
|
||||
|
||||
|
||||
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
|
||||
|
||||
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
|
||||
|
||||
/* cipher suite selectors */
|
||||
#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
|
||||
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
|
||||
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
|
||||
/* reserved: 0x000FAC03 */
|
||||
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
|
||||
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
|
||||
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
|
||||
|
||||
/* AKM suite selectors */
|
||||
#define WLAN_AKM_SUITE_8021X 0x000FAC01
|
||||
#define WLAN_AKM_SUITE_PSK 0x000FAC02
|
||||
|
||||
#endif /* IEEE802_11_DEFS_H */
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#ifndef VERSION_STR_POSTFIX
|
||||
#define VERSION_STR_POSTFIX ""
|
||||
#endif /* VERSION_STR_POSTFIX */
|
||||
|
||||
#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX
|
||||
|
||||
#endif /* VERSION_H */
|
|
@ -1,927 +0,0 @@
|
|||
/*
|
||||
* WPA/RSN - Shared functions for supplicant and authenticator
|
||||
* 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 "common.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "defs.h"
|
||||
#include "wpa_common.h"
|
||||
|
||||
|
||||
/**
|
||||
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
|
||||
* @key: EAPOL-Key Key Confirmation Key (KCK)
|
||||
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
|
||||
* @buf: Pointer to the beginning of the EAPOL header (version field)
|
||||
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
|
||||
* @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
|
||||
* to be cleared (all zeroes) when calling this function.
|
||||
*
|
||||
* Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
|
||||
* description of the Key MIC calculation. It includes packet data from the
|
||||
* beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
|
||||
* happened during final editing of the standard and the correct behavior is
|
||||
* defined in the last draft (IEEE 802.11i/D10).
|
||||
*/
|
||||
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
|
||||
u8 *mic)
|
||||
{
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
|
||||
switch (ver) {
|
||||
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
|
||||
return hmac_md5(key, 16, buf, len, mic);
|
||||
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
|
||||
if (hmac_sha1(key, 16, buf, len, hash))
|
||||
return -1;
|
||||
os_memcpy(mic, hash, MD5_MAC_LEN);
|
||||
break;
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
|
||||
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
|
||||
return omac1_aes_128(key, buf, len, mic);
|
||||
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
|
||||
* @pmk: Pairwise master key
|
||||
* @pmk_len: Length of PMK
|
||||
* @label: Label to use in derivation
|
||||
* @addr1: AA or SA
|
||||
* @addr2: SA or AA
|
||||
* @nonce1: ANonce or SNonce
|
||||
* @nonce2: SNonce or ANonce
|
||||
* @ptk: Buffer for pairwise transient key
|
||||
* @ptk_len: Length of PTK
|
||||
* @use_sha256: Whether to use SHA256-based KDF
|
||||
*
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
* PTK = PRF-X(PMK, "Pairwise key expansion",
|
||||
* Min(AA, SA) || Max(AA, SA) ||
|
||||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
|
||||
*
|
||||
* STK = PRF-X(SMK, "Peer key expansion",
|
||||
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
|
||||
* Min(INonce, PNonce) || Max(INonce, PNonce))
|
||||
*/
|
||||
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
const u8 *nonce1, const u8 *nonce2,
|
||||
u8 *ptk, size_t ptk_len, int use_sha256)
|
||||
{
|
||||
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
|
||||
|
||||
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
|
||||
os_memcpy(data, addr1, ETH_ALEN);
|
||||
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
|
||||
} else {
|
||||
os_memcpy(data, addr2, ETH_ALEN);
|
||||
os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
|
||||
os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
|
||||
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
|
||||
WPA_NONCE_LEN);
|
||||
} else {
|
||||
os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
|
||||
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
|
||||
WPA_NONCE_LEN);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (use_sha256)
|
||||
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
|
||||
ptk, ptk_len);
|
||||
else
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
|
||||
ptk_len);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
|
||||
MAC2STR(addr1), MAC2STR(addr2));
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
|
||||
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
|
||||
const u8 *ftie, size_t ftie_len,
|
||||
const u8 *rsnie, size_t rsnie_len,
|
||||
const u8 *ric, size_t ric_len, u8 *mic)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
size_t buf_len;
|
||||
|
||||
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
|
||||
buf = os_malloc(buf_len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
pos = buf;
|
||||
os_memcpy(pos, sta_addr, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
os_memcpy(pos, ap_addr, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
*pos++ = transaction_seqnum;
|
||||
if (rsnie) {
|
||||
os_memcpy(pos, rsnie, rsnie_len);
|
||||
pos += rsnie_len;
|
||||
}
|
||||
if (mdie) {
|
||||
os_memcpy(pos, mdie, mdie_len);
|
||||
pos += mdie_len;
|
||||
}
|
||||
if (ftie) {
|
||||
struct rsn_ftie *_ftie;
|
||||
os_memcpy(pos, ftie, ftie_len);
|
||||
if (ftie_len < 2 + sizeof(*_ftie)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
_ftie = (struct rsn_ftie *) (pos + 2);
|
||||
os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
|
||||
pos += ftie_len;
|
||||
}
|
||||
if (ric) {
|
||||
os_memcpy(pos, ric, ric_len);
|
||||
pos += ric_len;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
|
||||
if (omac1_aes_128(kck, buf, pos - buf, mic)) {
|
||||
os_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_WPA2
|
||||
static int rsn_selector_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
|
||||
return WPA_CIPHER_NONE;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
|
||||
return WPA_CIPHER_WEP40;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
|
||||
return WPA_CIPHER_TKIP;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
|
||||
return WPA_CIPHER_CCMP;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
|
||||
return WPA_CIPHER_WEP104;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
|
||||
return WPA_CIPHER_AES_128_CMAC;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int rsn_key_mgmt_to_bitfield(const u8 *s)
|
||||
{
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
|
||||
return WPA_KEY_MGMT_IEEE8021X;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
|
||||
return WPA_KEY_MGMT_PSK;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
|
||||
return WPA_KEY_MGMT_FT_IEEE8021X;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
|
||||
return WPA_KEY_MGMT_FT_PSK;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
|
||||
return WPA_KEY_MGMT_IEEE8021X_SHA256;
|
||||
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
|
||||
return WPA_KEY_MGMT_PSK_SHA256;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_WPA2 */
|
||||
|
||||
|
||||
/**
|
||||
* wpa_parse_wpa_ie_rsn - Parse RSN IE
|
||||
* @rsn_ie: Buffer containing RSN IE
|
||||
* @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
|
||||
* @data: Pointer to structure that will be filled in with parsed data
|
||||
* Returns: 0 on success, <0 on failure
|
||||
*/
|
||||
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data)
|
||||
{
|
||||
#ifndef CONFIG_NO_WPA2
|
||||
const struct rsn_ie_hdr *hdr;
|
||||
const u8 *pos;
|
||||
int left;
|
||||
int i, count;
|
||||
|
||||
os_memset(data, 0, sizeof(*data));
|
||||
data->proto = WPA_PROTO_RSN;
|
||||
data->pairwise_cipher = WPA_CIPHER_CCMP;
|
||||
data->group_cipher = WPA_CIPHER_CCMP;
|
||||
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
data->capabilities = 0;
|
||||
data->pmkid = NULL;
|
||||
data->num_pmkid = 0;
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
|
||||
#else /* CONFIG_IEEE80211W */
|
||||
data->mgmt_group_cipher = 0;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
if (rsn_ie_len == 0) {
|
||||
/* No RSN IE - fail silently */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
|
||||
__func__, (unsigned long) rsn_ie_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr = (const struct rsn_ie_hdr *) rsn_ie;
|
||||
|
||||
if (hdr->elem_id != WLAN_EID_RSN ||
|
||||
hdr->len != rsn_ie_len - 2 ||
|
||||
WPA_GET_LE16(hdr->version) != RSN_VERSION) {
|
||||
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
|
||||
__func__);
|
||||
return -2;
|
||||
}
|
||||
|
||||
pos = (const u8 *) (hdr + 1);
|
||||
left = rsn_ie_len - sizeof(*hdr);
|
||||
|
||||
if (left >= RSN_SELECTOR_LEN) {
|
||||
data->group_cipher = rsn_selector_to_bitfield(pos);
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
|
||||
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
|
||||
"cipher", __func__);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
} else if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
|
||||
__func__, left);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->pairwise_cipher = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
return -4;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
|
||||
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
|
||||
"pairwise cipher", __func__);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
} else if (left == 1) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
|
||||
__func__);
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->key_mgmt = 0;
|
||||
count = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
return -6;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
}
|
||||
} else if (left == 1) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
|
||||
__func__);
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->capabilities = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->num_pmkid = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
if (left < (int) data->num_pmkid * PMKID_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
|
||||
"(num_pmkid=%lu left=%d)",
|
||||
__func__, (unsigned long) data->num_pmkid,
|
||||
left);
|
||||
data->num_pmkid = 0;
|
||||
return -9;
|
||||
} else {
|
||||
data->pmkid = pos;
|
||||
pos += data->num_pmkid * PMKID_LEN;
|
||||
left -= data->num_pmkid * PMKID_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (left >= 4) {
|
||||
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
|
||||
if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Unsupported management "
|
||||
"group cipher 0x%x", __func__,
|
||||
data->mgmt_group_cipher);
|
||||
return -10;
|
||||
}
|
||||
pos += RSN_SELECTOR_LEN;
|
||||
left -= RSN_SELECTOR_LEN;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
|
||||
__func__, left);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_NO_WPA2 */
|
||||
return -1;
|
||||
#endif /* CONFIG_NO_WPA2 */
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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->proto = WPA_PROTO_WPA;
|
||||
data->pairwise_cipher = WPA_CIPHER_TKIP;
|
||||
data->group_cipher = WPA_CIPHER_TKIP;
|
||||
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
|
||||
data->capabilities = 0;
|
||||
data->pmkid = NULL;
|
||||
data->num_pmkid = 0;
|
||||
data->mgmt_group_cipher = 0;
|
||||
|
||||
if (wpa_ie_len == 0) {
|
||||
/* No WPA IE - fail silently */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
|
||||
__func__, (unsigned long) wpa_ie_len);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
|
||||
__func__);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
|
||||
__func__, left);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
|
||||
__func__);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
|
||||
"count %u left %u", __func__, count, left);
|
||||
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) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
|
||||
__func__);
|
||||
return -7;
|
||||
}
|
||||
|
||||
if (left >= 2) {
|
||||
data->capabilities = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
left -= 2;
|
||||
}
|
||||
|
||||
if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
|
||||
__func__, left);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
|
||||
/**
|
||||
* wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
|
||||
*
|
||||
* IEEE Std 802.11r-2008 - 8.5.1.5.3
|
||||
*/
|
||||
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
|
||||
{
|
||||
u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
|
||||
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
|
||||
u8 *pos, r0_key_data[48], hash[32];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
/*
|
||||
* R0-Key-Data = KDF-384(XXKey, "FT-R0",
|
||||
* SSIDlength || SSID || MDID || R0KHlength ||
|
||||
* R0KH-ID || S0KH-ID)
|
||||
* XXKey is either the second 256 bits of MSK or PSK.
|
||||
* PMK-R0 = L(R0-Key-Data, 0, 256)
|
||||
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
|
||||
*/
|
||||
if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
|
||||
return;
|
||||
pos = buf;
|
||||
*pos++ = ssid_len;
|
||||
os_memcpy(pos, ssid, ssid_len);
|
||||
pos += ssid_len;
|
||||
os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
|
||||
pos += MOBILITY_DOMAIN_ID_LEN;
|
||||
*pos++ = r0kh_id_len;
|
||||
os_memcpy(pos, r0kh_id, r0kh_id_len);
|
||||
pos += r0kh_id_len;
|
||||
os_memcpy(pos, s0kh_id, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
|
||||
sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
|
||||
r0_key_data, sizeof(r0_key_data));
|
||||
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
|
||||
|
||||
/*
|
||||
* PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
|
||||
*/
|
||||
addr[0] = (const u8 *) "FT-R0N";
|
||||
len[0] = 6;
|
||||
addr[1] = r0_key_data + PMK_LEN;
|
||||
len[1] = 16;
|
||||
|
||||
sha256_vector(2, addr, len, hash);
|
||||
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_derive_pmk_r1_name - Derive PMKR1Name
|
||||
*
|
||||
* IEEE Std 802.11r-2008 - 8.5.1.5.4
|
||||
*/
|
||||
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
|
||||
const u8 *s1kh_id, u8 *pmk_r1_name)
|
||||
{
|
||||
u8 hash[32];
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
|
||||
/*
|
||||
* PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
|
||||
* R1KH-ID || S1KH-ID))
|
||||
*/
|
||||
addr[0] = (const u8 *) "FT-R1N";
|
||||
len[0] = 6;
|
||||
addr[1] = pmk_r0_name;
|
||||
len[1] = WPA_PMK_NAME_LEN;
|
||||
addr[2] = r1kh_id;
|
||||
len[2] = FT_R1KH_ID_LEN;
|
||||
addr[3] = s1kh_id;
|
||||
len[3] = ETH_ALEN;
|
||||
|
||||
sha256_vector(4, addr, len, hash);
|
||||
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
|
||||
*
|
||||
* IEEE Std 802.11r-2008 - 8.5.1.5.4
|
||||
*/
|
||||
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
|
||||
const u8 *r1kh_id, const u8 *s1kh_id,
|
||||
u8 *pmk_r1, u8 *pmk_r1_name)
|
||||
{
|
||||
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
|
||||
u8 *pos;
|
||||
|
||||
/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
|
||||
pos = buf;
|
||||
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
|
||||
pos += FT_R1KH_ID_LEN;
|
||||
os_memcpy(pos, s1kh_id, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
|
||||
sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
|
||||
|
||||
wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
|
||||
*
|
||||
* IEEE Std 802.11r-2008 - 8.5.1.5.5
|
||||
*/
|
||||
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
|
||||
const u8 *sta_addr, const u8 *bssid,
|
||||
const u8 *pmk_r1_name,
|
||||
u8 *ptk, size_t ptk_len, u8 *ptk_name)
|
||||
{
|
||||
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
|
||||
u8 *pos, hash[32];
|
||||
const u8 *addr[6];
|
||||
size_t len[6];
|
||||
|
||||
/*
|
||||
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
|
||||
* BSSID || STA-ADDR)
|
||||
*/
|
||||
pos = buf;
|
||||
os_memcpy(pos, snonce, WPA_NONCE_LEN);
|
||||
pos += WPA_NONCE_LEN;
|
||||
os_memcpy(pos, anonce, WPA_NONCE_LEN);
|
||||
pos += WPA_NONCE_LEN;
|
||||
os_memcpy(pos, bssid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
os_memcpy(pos, sta_addr, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
|
||||
sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
|
||||
|
||||
/*
|
||||
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
|
||||
* ANonce || BSSID || STA-ADDR))
|
||||
*/
|
||||
addr[0] = pmk_r1_name;
|
||||
len[0] = WPA_PMK_NAME_LEN;
|
||||
addr[1] = (const u8 *) "FT-PTKN";
|
||||
len[1] = 7;
|
||||
addr[2] = snonce;
|
||||
len[2] = WPA_NONCE_LEN;
|
||||
addr[3] = anonce;
|
||||
len[3] = WPA_NONCE_LEN;
|
||||
addr[4] = bssid;
|
||||
len[4] = ETH_ALEN;
|
||||
addr[5] = sta_addr;
|
||||
len[5] = ETH_ALEN;
|
||||
|
||||
sha256_vector(6, addr, len, hash);
|
||||
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_cipher_txt - Convert cipher suite to a text string
|
||||
* @cipher: Cipher suite (WPA_CIPHER_* enum)
|
||||
* Returns: Pointer to a text string of the cipher suite name
|
||||
*/
|
||||
const char * wpa_cipher_txt(int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_NONE:
|
||||
return "NONE";
|
||||
case WPA_CIPHER_WEP40:
|
||||
return "WEP-40";
|
||||
case WPA_CIPHER_WEP104:
|
||||
return "WEP-104";
|
||||
case WPA_CIPHER_TKIP:
|
||||
return "TKIP";
|
||||
case WPA_CIPHER_CCMP:
|
||||
return "CCMP";
|
||||
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
|
||||
return "CCMP+TKIP";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_key_mgmt_txt - Convert key management suite to a text string
|
||||
* @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
|
||||
* @proto: WPA/WPA2 version (WPA_PROTO_*)
|
||||
* Returns: Pointer to a text string of the key management suite name
|
||||
*/
|
||||
const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
|
||||
{
|
||||
switch (key_mgmt) {
|
||||
case WPA_KEY_MGMT_IEEE8021X:
|
||||
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
|
||||
return "WPA2+WPA/IEEE 802.1X/EAP";
|
||||
return proto == WPA_PROTO_RSN ?
|
||||
"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
|
||||
case WPA_KEY_MGMT_PSK:
|
||||
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
|
||||
return "WPA2-PSK+WPA-PSK";
|
||||
return proto == WPA_PROTO_RSN ?
|
||||
"WPA2-PSK" : "WPA-PSK";
|
||||
case WPA_KEY_MGMT_NONE:
|
||||
return "NONE";
|
||||
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
|
||||
return "IEEE 802.1X (no WPA)";
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
case WPA_KEY_MGMT_FT_IEEE8021X:
|
||||
return "FT-EAP";
|
||||
case WPA_KEY_MGMT_FT_PSK:
|
||||
return "FT-PSK";
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
case WPA_KEY_MGMT_IEEE8021X_SHA256:
|
||||
return "WPA2-EAP-SHA256";
|
||||
case WPA_KEY_MGMT_PSK_SHA256:
|
||||
return "WPA2-PSK-SHA256";
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wpa_compare_rsn_ie(int ft_initial_assoc,
|
||||
const u8 *ie1, size_t ie1len,
|
||||
const u8 *ie2, size_t ie2len)
|
||||
{
|
||||
if (ie1 == NULL || ie2 == NULL)
|
||||
return -1;
|
||||
|
||||
if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
|
||||
return 0; /* identical IEs */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (ft_initial_assoc) {
|
||||
struct wpa_ie_data ie1d, ie2d;
|
||||
/*
|
||||
* The PMKID-List in RSN IE is different between Beacon/Probe
|
||||
* Response/(Re)Association Request frames and EAPOL-Key
|
||||
* messages in FT initial mobility domain association. Allow
|
||||
* for this, but verify that other parts of the RSN IEs are
|
||||
* identical.
|
||||
*/
|
||||
if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
|
||||
wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
|
||||
return -1;
|
||||
if (ie1d.proto == ie2d.proto &&
|
||||
ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
|
||||
ie1d.group_cipher == ie2d.group_cipher &&
|
||||
ie1d.key_mgmt == ie2d.key_mgmt &&
|
||||
ie1d.capabilities == ie2d.capabilities &&
|
||||
ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
|
||||
{
|
||||
u8 *start, *end, *rpos, *rend;
|
||||
int added = 0;
|
||||
|
||||
start = ies;
|
||||
end = ies + ies_len;
|
||||
|
||||
while (start < end) {
|
||||
if (*start == WLAN_EID_RSN)
|
||||
break;
|
||||
start += 2 + start[1];
|
||||
}
|
||||
if (start >= end) {
|
||||
wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
|
||||
"IEs data");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
|
||||
start, 2 + start[1]);
|
||||
|
||||
/* Find start of PMKID-Count */
|
||||
rpos = start + 2;
|
||||
rend = rpos + start[1];
|
||||
|
||||
/* Skip Version and Group Data Cipher Suite */
|
||||
rpos += 2 + 4;
|
||||
/* Skip Pairwise Cipher Suite Count and List */
|
||||
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
|
||||
/* Skip AKM Suite Count and List */
|
||||
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
|
||||
|
||||
if (rpos == rend) {
|
||||
/* Add RSN Capabilities */
|
||||
os_memmove(rpos + 2, rpos, end - rpos);
|
||||
*rpos++ = 0;
|
||||
*rpos++ = 0;
|
||||
} else {
|
||||
/* Skip RSN Capabilities */
|
||||
rpos += 2;
|
||||
if (rpos > rend) {
|
||||
wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
|
||||
"IEs data");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rpos == rend) {
|
||||
/* No PMKID-Count field included; add it */
|
||||
os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
|
||||
WPA_PUT_LE16(rpos, 1);
|
||||
rpos += 2;
|
||||
os_memcpy(rpos, pmkid, PMKID_LEN);
|
||||
added += 2 + PMKID_LEN;
|
||||
start[1] += 2 + PMKID_LEN;
|
||||
} else {
|
||||
/* PMKID-Count was included; use it */
|
||||
if (WPA_GET_LE16(rpos) != 0) {
|
||||
wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
|
||||
"in RSN IE in EAPOL-Key data");
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_LE16(rpos, 1);
|
||||
rpos += 2;
|
||||
os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
|
||||
os_memcpy(rpos, pmkid, PMKID_LEN);
|
||||
added += PMKID_LEN;
|
||||
start[1] += PMKID_LEN;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
|
||||
"(PMKID inserted)", start, 2 + start[1]);
|
||||
|
||||
return added;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
|
@ -1,361 +0,0 @@
|
|||
/*
|
||||
* WPA definitions shared between hostapd and wpa_supplicant
|
||||
* 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 WPA_COMMON_H
|
||||
#define WPA_COMMON_H
|
||||
|
||||
#define WPA_MAX_SSID_LEN 32
|
||||
|
||||
/* IEEE 802.11i */
|
||||
#define PMKID_LEN 16
|
||||
#define PMK_LEN 32
|
||||
#define WPA_REPLAY_COUNTER_LEN 8
|
||||
#define WPA_NONCE_LEN 32
|
||||
#define WPA_KEY_RSC_LEN 8
|
||||
#define WPA_GMK_LEN 32
|
||||
#define WPA_GTK_MAX_LEN 32
|
||||
|
||||
#define WPA_SELECTOR_LEN 4
|
||||
#define WPA_VERSION 1
|
||||
#define RSN_SELECTOR_LEN 4
|
||||
#define RSN_VERSION 1
|
||||
|
||||
#define RSN_SELECTOR(a, b, c, d) \
|
||||
((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
|
||||
(u32) (d))
|
||||
|
||||
#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
|
||||
#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
|
||||
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
|
||||
#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
|
||||
#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
|
||||
#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
|
||||
#if 0
|
||||
#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
|
||||
#endif
|
||||
#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
|
||||
#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
|
||||
|
||||
|
||||
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
|
||||
#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
|
||||
#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
|
||||
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
|
||||
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
|
||||
|
||||
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
|
||||
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
|
||||
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
|
||||
#if 0
|
||||
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
|
||||
#endif
|
||||
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
|
||||
#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
|
||||
|
||||
/* EAPOL-Key Key Data Encapsulation
|
||||
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
|
||||
*/
|
||||
#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
|
||||
#if 0
|
||||
#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
|
||||
#endif
|
||||
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
|
||||
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
|
||||
#ifdef CONFIG_PEERKEY
|
||||
#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
|
||||
#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
|
||||
#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
|
||||
#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
|
||||
|
||||
#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
|
||||
#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
|
||||
|
||||
#define RSN_NUM_REPLAY_COUNTERS_1 0
|
||||
#define RSN_NUM_REPLAY_COUNTERS_2 1
|
||||
#define RSN_NUM_REPLAY_COUNTERS_4 2
|
||||
#define RSN_NUM_REPLAY_COUNTERS_16 3
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
#define WPA_IGTK_LEN 16
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
|
||||
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
|
||||
#define WPA_CAPABILITY_PREAUTH BIT(0)
|
||||
#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
|
||||
/* B2-B3: PTKSA Replay Counter */
|
||||
/* B4-B5: GTKSA Replay Counter */
|
||||
#define WPA_CAPABILITY_MFPR BIT(6)
|
||||
#define WPA_CAPABILITY_MFPC BIT(7)
|
||||
/* B8: Reserved */
|
||||
#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
|
||||
#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
|
||||
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
|
||||
#define WPA_CAPABILITY_PBAC BIT(12)
|
||||
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
|
||||
/* B14-B15: Reserved */
|
||||
|
||||
|
||||
/* IEEE 802.11r */
|
||||
#define MOBILITY_DOMAIN_ID_LEN 2
|
||||
#define FT_R0KH_ID_MAX_LEN 48
|
||||
#define FT_R1KH_ID_LEN 6
|
||||
#define WPA_PMK_NAME_LEN 16
|
||||
|
||||
|
||||
/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
|
||||
#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
|
||||
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
|
||||
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
|
||||
#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
|
||||
#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
|
||||
/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
|
||||
#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
|
||||
#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
|
||||
#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
|
||||
#define WPA_KEY_INFO_TXRX BIT(6) /* group */
|
||||
#define WPA_KEY_INFO_ACK BIT(7)
|
||||
#define WPA_KEY_INFO_MIC BIT(8)
|
||||
#define WPA_KEY_INFO_SECURE BIT(9)
|
||||
#define WPA_KEY_INFO_ERROR BIT(10)
|
||||
#define WPA_KEY_INFO_REQUEST BIT(11)
|
||||
#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
|
||||
#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
|
||||
|
||||
|
||||
struct wpa_eapol_key {
|
||||
u8 type;
|
||||
/* Note: key_info, key_length, and key_data_length are unaligned */
|
||||
u8 key_info[2]; /* big endian */
|
||||
u8 key_length[2]; /* big endian */
|
||||
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
u8 key_nonce[WPA_NONCE_LEN];
|
||||
u8 key_iv[16];
|
||||
u8 key_rsc[WPA_KEY_RSC_LEN];
|
||||
u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
|
||||
u8 key_mic[16];
|
||||
u8 key_data_length[2]; /* big endian */
|
||||
/* followed by key_data_length bytes of key_data */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/**
|
||||
* struct wpa_ptk - WPA Pairwise Transient Key
|
||||
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||
*/
|
||||
struct wpa_ptk {
|
||||
u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
|
||||
u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
|
||||
u8 tk1[16]; /* Temporal Key 1 (TK1) */
|
||||
union {
|
||||
u8 tk2[16]; /* Temporal Key 2 (TK2) */
|
||||
struct {
|
||||
u8 tx_mic_key[8];
|
||||
u8 rx_mic_key[8];
|
||||
} auth;
|
||||
} u;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
/* WPA IE version 1
|
||||
* 00-50-f2:1 (OUI:OUI type)
|
||||
* 0x01 0x00 (version; little endian)
|
||||
* (all following fields are optional:)
|
||||
* Group Suite Selector (4 octets) (default: TKIP)
|
||||
* Pairwise Suite Count (2 octets, little endian) (default: 1)
|
||||
* Pairwise Suite List (4 * n octets) (default: TKIP)
|
||||
* Authenticated Key Management Suite Count (2 octets, little endian)
|
||||
* (default: 1)
|
||||
* Authenticated Key Management Suite List (4 * n octets)
|
||||
* (default: unspec 802.1X)
|
||||
* WPA Capabilities (2 octets, little endian) (default: 0)
|
||||
*/
|
||||
|
||||
struct wpa_ie_hdr {
|
||||
u8 elem_id;
|
||||
u8 len;
|
||||
u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
|
||||
u8 version[2]; /* little endian */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
/* 1/4: PMKID
|
||||
* 2/4: RSN IE
|
||||
* 3/4: one or two RSN IEs + GTK IE (encrypted)
|
||||
* 4/4: empty
|
||||
* 1/2: GTK IE (encrypted)
|
||||
* 2/2: empty
|
||||
*/
|
||||
|
||||
/* RSN IE version 1
|
||||
* 0x01 0x00 (version; little endian)
|
||||
* (all following fields are optional:)
|
||||
* Group Suite Selector (4 octets) (default: CCMP)
|
||||
* Pairwise Suite Count (2 octets, little endian) (default: 1)
|
||||
* Pairwise Suite List (4 * n octets) (default: CCMP)
|
||||
* Authenticated Key Management Suite Count (2 octets, little endian)
|
||||
* (default: 1)
|
||||
* Authenticated Key Management Suite List (4 * n octets)
|
||||
* (default: unspec 802.1X)
|
||||
* RSN Capabilities (2 octets, little endian) (default: 0)
|
||||
* PMKID Count (2 octets) (default: 0)
|
||||
* PMKID List (16 * n octets)
|
||||
* Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
|
||||
*/
|
||||
|
||||
struct rsn_ie_hdr {
|
||||
u8 elem_id; /* WLAN_EID_RSN */
|
||||
u8 len;
|
||||
u8 version[2]; /* little endian */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
#ifdef CONFIG_PEERKEY
|
||||
enum {
|
||||
STK_MUI_4WAY_STA_AP = 1,
|
||||
STK_MUI_4WAY_STAT_STA = 2,
|
||||
STK_MUI_GTK = 3,
|
||||
STK_MUI_SMK = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
STK_ERR_STA_NR = 1,
|
||||
STK_ERR_STA_NRSN = 2,
|
||||
STK_ERR_CPHR_NS = 3,
|
||||
STK_ERR_NO_STSL = 4
|
||||
};
|
||||
#endif /* CONFIG_PEERKEY */
|
||||
|
||||
struct rsn_error_kde {
|
||||
be16 mui;
|
||||
be16 error_type;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
struct wpa_igtk_kde {
|
||||
u8 keyid[2];
|
||||
u8 pn[6];
|
||||
u8 igtk[WPA_IGTK_LEN];
|
||||
} STRUCT_PACKED;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
struct rsn_mdie {
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 ft_capab;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
|
||||
#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
|
||||
|
||||
struct rsn_ftie {
|
||||
u8 mic_control[2];
|
||||
u8 mic[16];
|
||||
u8 anonce[WPA_NONCE_LEN];
|
||||
u8 snonce[WPA_NONCE_LEN];
|
||||
/* followed by optional parameters */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define FTIE_SUBELEM_R1KH_ID 1
|
||||
#define FTIE_SUBELEM_GTK 2
|
||||
#define FTIE_SUBELEM_R0KH_ID 3
|
||||
#define FTIE_SUBELEM_IGTK 4
|
||||
|
||||
struct rsn_rdie {
|
||||
u8 id;
|
||||
u8 descr_count;
|
||||
le16 status_code;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
|
||||
u8 *mic);
|
||||
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
const u8 *nonce1, const u8 *nonce2,
|
||||
u8 *ptk, size_t ptk_len, int use_sha256);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
|
||||
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
|
||||
const u8 *ftie, size_t ftie_len,
|
||||
const u8 *rsnie, size_t rsnie_len,
|
||||
const u8 *ric, size_t ric_len, u8 *mic);
|
||||
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
|
||||
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
|
||||
const u8 *s1kh_id, u8 *pmk_r1_name);
|
||||
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
|
||||
const u8 *r1kh_id, const u8 *s1kh_id,
|
||||
u8 *pmk_r1, u8 *pmk_r1_name);
|
||||
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
|
||||
const u8 *sta_addr, const u8 *bssid,
|
||||
const u8 *pmk_r1_name,
|
||||
u8 *ptk, size_t ptk_len, u8 *ptk_name);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
struct wpa_ie_data {
|
||||
int proto;
|
||||
int pairwise_cipher;
|
||||
int group_cipher;
|
||||
int key_mgmt;
|
||||
int capabilities;
|
||||
size_t num_pmkid;
|
||||
const u8 *pmkid;
|
||||
int mgmt_group_cipher;
|
||||
};
|
||||
|
||||
|
||||
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
struct wpa_ie_data *data);
|
||||
|
||||
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||
u8 *pmkid, int use_sha256);
|
||||
|
||||
const char * wpa_cipher_txt(int cipher);
|
||||
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
|
||||
int wpa_compare_rsn_ie(int ft_initial_assoc,
|
||||
const u8 *ie1, size_t ie1len,
|
||||
const u8 *ie2, size_t ie2len);
|
||||
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
|
||||
|
||||
#endif /* WPA_COMMON_H */
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* wpa_supplicant/hostapd control interface library
|
||||
* Copyright (c) 2004-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 WPA_CTRL_H
|
||||
#define WPA_CTRL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* wpa_supplicant control interface - fixed message prefixes */
|
||||
|
||||
/** Interactive request for identity/password/pin */
|
||||
#define WPA_CTRL_REQ "CTRL-REQ-"
|
||||
|
||||
/** Response to identity/password/pin request */
|
||||
#define WPA_CTRL_RSP "CTRL-RSP-"
|
||||
|
||||
/* Event messages with fixed prefix */
|
||||
/** Authentication completed successfully and data connection enabled */
|
||||
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
|
||||
/** Disconnected, data connection is not available */
|
||||
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
|
||||
/** Association rejected during connection attempt */
|
||||
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
|
||||
/** wpa_supplicant is exiting */
|
||||
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
|
||||
/** Password change was completed successfully */
|
||||
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
|
||||
/** EAP-Request/Notification received */
|
||||
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
|
||||
/** EAP authentication started (EAP-Request/Identity received) */
|
||||
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
|
||||
/** EAP method proposed by the server */
|
||||
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
|
||||
/** EAP method selected */
|
||||
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
|
||||
/** EAP peer certificate from TLS */
|
||||
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
|
||||
/** EAP TLS certificate chain validation error */
|
||||
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
|
||||
/** EAP authentication completed successfully */
|
||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||
/** EAP authentication failed (EAP-Failure received) */
|
||||
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
|
||||
/** New scan results available */
|
||||
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
|
||||
/** wpa_supplicant state change */
|
||||
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
|
||||
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
|
||||
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
|
||||
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
|
||||
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
|
||||
|
||||
/** WPS overlap detected in PBC mode */
|
||||
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
|
||||
/** Available WPS AP with active PBC found in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
|
||||
/** Available WPS AP with our address as authorized in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
|
||||
/** Available WPS AP with recently selected PIN registrar found in scan results
|
||||
*/
|
||||
#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
|
||||
/** Available WPS AP found in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
|
||||
/** A new credential received */
|
||||
#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
|
||||
/** M2D received */
|
||||
#define WPS_EVENT_M2D "WPS-M2D "
|
||||
/** WPS registration failed after M2/M2D */
|
||||
#define WPS_EVENT_FAIL "WPS-FAIL "
|
||||
/** WPS registration completed successfully */
|
||||
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
|
||||
/** WPS enrollment attempt timed out and was terminated */
|
||||
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
|
||||
|
||||
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
|
||||
|
||||
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
|
||||
|
||||
/* WPS ER events */
|
||||
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
|
||||
#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
|
||||
#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
|
||||
#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
|
||||
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
|
||||
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
|
||||
|
||||
/** P2P device found */
|
||||
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
|
||||
/** A P2P device requested GO negotiation, but we were not ready to start the
|
||||
* negotiation */
|
||||
#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
|
||||
#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
|
||||
#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
|
||||
#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
|
||||
#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
|
||||
#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
|
||||
#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
|
||||
#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
|
||||
#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
|
||||
/* parameters: <peer address> <PIN> */
|
||||
#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
|
||||
/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
|
||||
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
|
||||
/* parameters: <src addr> <update indicator> <TLVs> */
|
||||
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
|
||||
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
|
||||
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
|
||||
|
||||
/* hostapd control interface - fixed message prefixes */
|
||||
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
|
||||
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
|
||||
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
|
||||
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
|
||||
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
|
||||
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
|
||||
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
|
||||
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
|
||||
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
|
||||
|
||||
|
||||
/* wpa_supplicant/hostapd control interface access */
|
||||
|
||||
/**
|
||||
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
|
||||
* Returns: Pointer to abstract control interface data or %NULL on failure
|
||||
*
|
||||
* This function is used to open a control interface to wpa_supplicant/hostapd.
|
||||
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
|
||||
* is configured in wpa_supplicant/hostapd and other programs using the control
|
||||
* interface need to use matching path configuration.
|
||||
*/
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
*
|
||||
* This function is used to close a control interface.
|
||||
*/
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @cmd: Command; usually, ASCII text, e.g., "PING"
|
||||
* @cmd_len: Length of the cmd in bytes
|
||||
* @reply: Buffer for the response
|
||||
* @reply_len: Reply buffer length
|
||||
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
|
||||
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
|
||||
*
|
||||
* This function is used to send commands to wpa_supplicant/hostapd. Received
|
||||
* response will be written to reply and reply_len is set to the actual length
|
||||
* of the reply. This function will block for up to two seconds while waiting
|
||||
* for the reply. If unsolicited messages are received, the blocking time may
|
||||
* be longer.
|
||||
*
|
||||
* msg_cb can be used to register a callback function that will be called for
|
||||
* unsolicited messages received while waiting for the command response. These
|
||||
* messages may be received if wpa_ctrl_request() is called at the same time as
|
||||
* wpa_supplicant/hostapd is sending such a message. This can happen only if
|
||||
* the program has used wpa_ctrl_attach() to register itself as a monitor for
|
||||
* event messages. Alternatively to msg_cb, programs can register two control
|
||||
* interface connections and use one of them for commands and the other one for
|
||||
* receiving event messages, in other words, call wpa_ctrl_attach() only for
|
||||
* the control interface connection that will be used for event messages.
|
||||
*/
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len));
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_attach - Register as an event monitor for the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function registers the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
|
||||
* control interface connection starts receiving event messages that can be
|
||||
* read with wpa_ctrl_recv().
|
||||
*/
|
||||
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_detach - Unregister event monitor from the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function unregisters the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
|
||||
* wpa_ctrl_attach().
|
||||
*/
|
||||
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_recv - Receive a pending control interface message
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @reply: Buffer for the message data
|
||||
* @reply_len: Length of the reply buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function will receive a pending control interface message. This
|
||||
* function will block if no messages are available. The received response will
|
||||
* be written to reply and reply_len is set to the actual length of the reply.
|
||||
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
|
||||
* must have been used to register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_pending - Check whether there are pending event messages
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
|
||||
*
|
||||
* This function will check whether there are any pending control interface
|
||||
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
|
||||
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
|
||||
* register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: File descriptor used for the connection
|
||||
*
|
||||
* This function can be used to get the file descriptor that is used for the
|
||||
* control interface connection. The returned value can be used, e.g., with
|
||||
* select() while waiting for multiple events.
|
||||
*
|
||||
* The returned file descriptor must not be used directly for sending or
|
||||
* receiving packets; instead, the library functions wpa_ctrl_request() and
|
||||
* wpa_ctrl_recv() must be used for this.
|
||||
*/
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
#define WPA_CTRL_IFACE_PORT 9877
|
||||
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WPA_CTRL_H */
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* AES functions
|
||||
* Copyright (c) 2003-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 AES_H
|
||||
#define AES_H
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
void * aes_encrypt_init(const u8 *key, size_t len);
|
||||
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
|
||||
void aes_encrypt_deinit(void *ctx);
|
||||
void * aes_decrypt_init(const u8 *key, size_t len);
|
||||
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
|
||||
void aes_decrypt_deinit(void *ctx);
|
||||
|
||||
#endif /* AES_H */
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* AES-based functions
|
||||
*
|
||||
* - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
|
||||
* - One-Key CBC MAC (OMAC1) hash with AES-128
|
||||
* - AES-128 CTR mode encryption
|
||||
* - AES-128 EAX mode encryption/decryption
|
||||
* - AES-128 CBC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef AES_WRAP_H
|
||||
#define AES_WRAP_H
|
||||
|
||||
int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
|
||||
int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
|
||||
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len,
|
||||
u8 *mac);
|
||||
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
|
||||
u8 *mac);
|
||||
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
|
||||
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
|
||||
u8 *data, size_t data_len);
|
||||
int __must_check aes_128_eax_encrypt(const u8 *key,
|
||||
const u8 *nonce, size_t nonce_len,
|
||||
const u8 *hdr, size_t hdr_len,
|
||||
u8 *data, size_t data_len, u8 *tag);
|
||||
int __must_check aes_128_eax_decrypt(const u8 *key,
|
||||
const u8 *nonce, size_t nonce_len,
|
||||
const u8 *hdr, size_t hdr_len,
|
||||
u8 *data, size_t data_len, const u8 *tag);
|
||||
int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
|
||||
size_t data_len);
|
||||
int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
|
||||
size_t data_len);
|
||||
|
||||
#endif /* AES_WRAP_H */
|
|
@ -1,789 +0,0 @@
|
|||
/*
|
||||
* Crypto wrapper for Microsoft CryptoAPI
|
||||
* Copyright (c) 2005-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 <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#ifndef MS_ENH_RSA_AES_PROV
|
||||
#ifdef UNICODE
|
||||
#define MS_ENH_RSA_AES_PROV \
|
||||
L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
|
||||
#else
|
||||
#define MS_ENH_RSA_AES_PROV \
|
||||
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
|
||||
#endif
|
||||
#endif /* MS_ENH_RSA_AES_PROV */
|
||||
|
||||
#ifndef CALG_HMAC
|
||||
#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32_VERSION
|
||||
/*
|
||||
* MinGW does not yet include all the needed definitions for CryptoAPI, so
|
||||
* define here whatever extra is needed.
|
||||
*/
|
||||
|
||||
static BOOL WINAPI
|
||||
(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
|
||||
PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
|
||||
= NULL; /* to be loaded from crypt32.dll */
|
||||
|
||||
|
||||
static int mingw_load_crypto_func(void)
|
||||
{
|
||||
HINSTANCE dll;
|
||||
|
||||
/* MinGW does not yet have full CryptoAPI support, so load the needed
|
||||
* function here. */
|
||||
|
||||
if (CryptImportPublicKeyInfo)
|
||||
return 0;
|
||||
|
||||
dll = LoadLibrary("crypt32");
|
||||
if (dll == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
|
||||
"library");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CryptImportPublicKeyInfo = GetProcAddress(
|
||||
dll, "CryptImportPublicKeyInfo");
|
||||
if (CryptImportPublicKeyInfo == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
|
||||
"CryptImportPublicKeyInfo() address from "
|
||||
"crypt32 library");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* __MINGW32_VERSION */
|
||||
|
||||
static int mingw_load_crypto_func(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __MINGW32_VERSION */
|
||||
|
||||
|
||||
static void cryptoapi_report_error(const char *msg)
|
||||
{
|
||||
char *s, *pos;
|
||||
DWORD err = GetLastError();
|
||||
|
||||
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
|
||||
}
|
||||
|
||||
pos = s;
|
||||
while (*pos) {
|
||||
if (*pos == '\n' || *pos == '\r') {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
|
||||
LocalFree(s);
|
||||
}
|
||||
|
||||
|
||||
int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTHASH hash;
|
||||
size_t i;
|
||||
DWORD hlen;
|
||||
int ret = 0;
|
||||
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
|
||||
cryptoapi_report_error("CryptAcquireContext");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
|
||||
cryptoapi_report_error("CryptCreateHash");
|
||||
CryptReleaseContext(prov, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
|
||||
cryptoapi_report_error("CryptHashData");
|
||||
CryptDestroyHash(hash);
|
||||
CryptReleaseContext(prov, 0);
|
||||
}
|
||||
}
|
||||
|
||||
hlen = hash_len;
|
||||
if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
|
||||
cryptoapi_report_error("CryptGetHashParam");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
CryptDestroyHash(hash);
|
||||
CryptReleaseContext(prov, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
{
|
||||
u8 next, tmp;
|
||||
int i;
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTKEY ckey;
|
||||
DWORD dlen;
|
||||
struct {
|
||||
BLOBHEADER hdr;
|
||||
DWORD len;
|
||||
BYTE key[8];
|
||||
} key_blob;
|
||||
DWORD mode = CRYPT_MODE_ECB;
|
||||
|
||||
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob.hdr.reserved = 0;
|
||||
key_blob.hdr.aiKeyAlg = CALG_DES;
|
||||
key_blob.len = 8;
|
||||
|
||||
/* Add parity bits to the key */
|
||||
next = 0;
|
||||
for (i = 0; i < 7; i++) {
|
||||
tmp = key[i];
|
||||
key_blob.key[i] = (tmp >> i) | next | 1;
|
||||
next = tmp << (7 - i);
|
||||
}
|
||||
key_blob.key[i] = next | 1;
|
||||
|
||||
if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
|
||||
"%d", (int) GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
|
||||
&ckey)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
|
||||
(int) GetLastError());
|
||||
CryptReleaseContext(prov, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
|
||||
"failed: %d", (int) GetLastError());
|
||||
CryptDestroyKey(ckey);
|
||||
CryptReleaseContext(prov, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(cypher, clear, 8);
|
||||
dlen = 8;
|
||||
if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
|
||||
(int) GetLastError());
|
||||
os_memset(cypher, 0, 8);
|
||||
}
|
||||
|
||||
CryptDestroyKey(ckey);
|
||||
CryptReleaseContext(prov, 0);
|
||||
}
|
||||
|
||||
|
||||
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
struct aes_context {
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTKEY ckey;
|
||||
};
|
||||
|
||||
|
||||
void * aes_encrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
struct aes_context *akey;
|
||||
struct {
|
||||
BLOBHEADER hdr;
|
||||
DWORD len;
|
||||
BYTE key[16];
|
||||
} key_blob;
|
||||
DWORD mode = CRYPT_MODE_ECB;
|
||||
|
||||
if (len != 16)
|
||||
return NULL;
|
||||
|
||||
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob.hdr.reserved = 0;
|
||||
key_blob.hdr.aiKeyAlg = CALG_AES_128;
|
||||
key_blob.len = len;
|
||||
os_memcpy(key_blob.key, key, len);
|
||||
|
||||
akey = os_zalloc(sizeof(*akey));
|
||||
if (akey == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CryptAcquireContext(&akey->prov, NULL,
|
||||
MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
|
||||
"%d", (int) GetLastError());
|
||||
os_free(akey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
|
||||
0, 0, &akey->ckey)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
|
||||
(int) GetLastError());
|
||||
CryptReleaseContext(akey->prov, 0);
|
||||
os_free(akey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
|
||||
"failed: %d", (int) GetLastError());
|
||||
CryptDestroyKey(akey->ckey);
|
||||
CryptReleaseContext(akey->prov, 0);
|
||||
os_free(akey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return akey;
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
|
||||
{
|
||||
struct aes_context *akey = ctx;
|
||||
DWORD dlen;
|
||||
|
||||
os_memcpy(crypt, plain, 16);
|
||||
dlen = 16;
|
||||
if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
|
||||
(int) GetLastError());
|
||||
os_memset(crypt, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt_deinit(void *ctx)
|
||||
{
|
||||
struct aes_context *akey = ctx;
|
||||
if (akey) {
|
||||
CryptDestroyKey(akey->ckey);
|
||||
CryptReleaseContext(akey->prov, 0);
|
||||
os_free(akey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void * aes_decrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
return aes_encrypt_init(key, len);
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
|
||||
{
|
||||
struct aes_context *akey = ctx;
|
||||
DWORD dlen;
|
||||
|
||||
os_memcpy(plain, crypt, 16);
|
||||
dlen = 16;
|
||||
|
||||
if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
|
||||
(int) GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt_deinit(void *ctx)
|
||||
{
|
||||
aes_encrypt_deinit(ctx);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_hash {
|
||||
enum crypto_hash_alg alg;
|
||||
int error;
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTHASH hash;
|
||||
HCRYPTKEY key;
|
||||
};
|
||||
|
||||
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct crypto_hash *ctx;
|
||||
ALG_ID calg;
|
||||
struct {
|
||||
BLOBHEADER hdr;
|
||||
DWORD len;
|
||||
BYTE key[32];
|
||||
} key_blob;
|
||||
|
||||
os_memset(&key_blob, 0, sizeof(key_blob));
|
||||
switch (alg) {
|
||||
case CRYPTO_HASH_ALG_MD5:
|
||||
calg = CALG_MD5;
|
||||
break;
|
||||
case CRYPTO_HASH_ALG_SHA1:
|
||||
calg = CALG_SHA;
|
||||
break;
|
||||
case CRYPTO_HASH_ALG_HMAC_MD5:
|
||||
case CRYPTO_HASH_ALG_HMAC_SHA1:
|
||||
calg = CALG_HMAC;
|
||||
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob.hdr.reserved = 0;
|
||||
/*
|
||||
* Note: RC2 is not really used, but that can be used to
|
||||
* import HMAC keys of up to 16 byte long.
|
||||
* CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
|
||||
* be able to import longer keys (HMAC-SHA1 uses 20-byte key).
|
||||
*/
|
||||
key_blob.hdr.aiKeyAlg = CALG_RC2;
|
||||
key_blob.len = key_len;
|
||||
if (key_len > sizeof(key_blob.key))
|
||||
return NULL;
|
||||
os_memcpy(key_blob.key, key, key_len);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = os_zalloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx->alg = alg;
|
||||
|
||||
if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
|
||||
cryptoapi_report_error("CryptAcquireContext");
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (calg == CALG_HMAC) {
|
||||
#ifndef CRYPT_IPSEC_HMAC_KEY
|
||||
#define CRYPT_IPSEC_HMAC_KEY 0x00000100
|
||||
#endif
|
||||
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
|
||||
sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
|
||||
&ctx->key)) {
|
||||
cryptoapi_report_error("CryptImportKey");
|
||||
CryptReleaseContext(ctx->prov, 0);
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
|
||||
cryptoapi_report_error("CryptCreateHash");
|
||||
CryptReleaseContext(ctx->prov, 0);
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (calg == CALG_HMAC) {
|
||||
HMAC_INFO info;
|
||||
os_memset(&info, 0, sizeof(info));
|
||||
switch (alg) {
|
||||
case CRYPTO_HASH_ALG_HMAC_MD5:
|
||||
info.HashAlgid = CALG_MD5;
|
||||
break;
|
||||
case CRYPTO_HASH_ALG_HMAC_SHA1:
|
||||
info.HashAlgid = CALG_SHA;
|
||||
break;
|
||||
default:
|
||||
/* unreachable */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
|
||||
0)) {
|
||||
cryptoapi_report_error("CryptSetHashParam");
|
||||
CryptDestroyHash(ctx->hash);
|
||||
CryptReleaseContext(ctx->prov, 0);
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
|
||||
{
|
||||
if (ctx == NULL || ctx->error)
|
||||
return;
|
||||
|
||||
if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
|
||||
cryptoapi_report_error("CryptHashData");
|
||||
ctx->error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
|
||||
{
|
||||
int ret = 0;
|
||||
DWORD hlen;
|
||||
|
||||
if (ctx == NULL)
|
||||
return -2;
|
||||
|
||||
if (mac == NULL || len == NULL)
|
||||
goto done;
|
||||
|
||||
if (ctx->error) {
|
||||
ret = -2;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hlen = *len;
|
||||
if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
|
||||
cryptoapi_report_error("CryptGetHashParam");
|
||||
ret = -2;
|
||||
}
|
||||
*len = hlen;
|
||||
|
||||
done:
|
||||
if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
|
||||
ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
|
||||
CryptDestroyKey(ctx->key);
|
||||
|
||||
os_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_cipher {
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTKEY key;
|
||||
};
|
||||
|
||||
|
||||
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
|
||||
const u8 *iv, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct crypto_cipher *ctx;
|
||||
struct {
|
||||
BLOBHEADER hdr;
|
||||
DWORD len;
|
||||
BYTE key[32];
|
||||
} key_blob;
|
||||
DWORD mode = CRYPT_MODE_CBC;
|
||||
|
||||
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob.hdr.reserved = 0;
|
||||
key_blob.len = key_len;
|
||||
if (key_len > sizeof(key_blob.key))
|
||||
return NULL;
|
||||
os_memcpy(key_blob.key, key, key_len);
|
||||
|
||||
switch (alg) {
|
||||
case CRYPTO_CIPHER_ALG_AES:
|
||||
if (key_len == 32)
|
||||
key_blob.hdr.aiKeyAlg = CALG_AES_256;
|
||||
else if (key_len == 24)
|
||||
key_blob.hdr.aiKeyAlg = CALG_AES_192;
|
||||
else
|
||||
key_blob.hdr.aiKeyAlg = CALG_AES_128;
|
||||
break;
|
||||
case CRYPTO_CIPHER_ALG_3DES:
|
||||
key_blob.hdr.aiKeyAlg = CALG_3DES;
|
||||
break;
|
||||
case CRYPTO_CIPHER_ALG_DES:
|
||||
key_blob.hdr.aiKeyAlg = CALG_DES;
|
||||
break;
|
||||
case CRYPTO_CIPHER_ALG_RC2:
|
||||
key_blob.hdr.aiKeyAlg = CALG_RC2;
|
||||
break;
|
||||
case CRYPTO_CIPHER_ALG_RC4:
|
||||
key_blob.hdr.aiKeyAlg = CALG_RC4;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = os_zalloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
|
||||
PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
||||
cryptoapi_report_error("CryptAcquireContext");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
|
||||
sizeof(key_blob), 0, 0, &ctx->key)) {
|
||||
cryptoapi_report_error("CryptImportKey");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
|
||||
cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
|
||||
cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
|
||||
fail3:
|
||||
CryptDestroyKey(ctx->key);
|
||||
fail2:
|
||||
CryptReleaseContext(ctx->prov, 0);
|
||||
fail1:
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
|
||||
u8 *crypt, size_t len)
|
||||
{
|
||||
DWORD dlen;
|
||||
|
||||
os_memcpy(crypt, plain, len);
|
||||
dlen = len;
|
||||
if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
|
||||
cryptoapi_report_error("CryptEncrypt");
|
||||
os_memset(crypt, 0, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
|
||||
u8 *plain, size_t len)
|
||||
{
|
||||
DWORD dlen;
|
||||
|
||||
os_memcpy(plain, crypt, len);
|
||||
dlen = len;
|
||||
if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
|
||||
cryptoapi_report_error("CryptDecrypt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void crypto_cipher_deinit(struct crypto_cipher *ctx)
|
||||
{
|
||||
CryptDestroyKey(ctx->key);
|
||||
CryptReleaseContext(ctx->prov, 0);
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_public_key {
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTKEY rsa;
|
||||
};
|
||||
|
||||
struct crypto_private_key {
|
||||
HCRYPTPROV prov;
|
||||
HCRYPTKEY rsa;
|
||||
};
|
||||
|
||||
|
||||
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
|
||||
{
|
||||
/* Use crypto_public_key_from_cert() instead. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_private_key * crypto_private_key_import(const u8 *key,
|
||||
size_t len,
|
||||
const char *passwd)
|
||||
{
|
||||
/* TODO */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct crypto_public_key *pk;
|
||||
PCCERT_CONTEXT cc;
|
||||
|
||||
pk = os_zalloc(sizeof(*pk));
|
||||
if (pk == NULL)
|
||||
return NULL;
|
||||
|
||||
cc = CertCreateCertificateContext(X509_ASN_ENCODING |
|
||||
PKCS_7_ASN_ENCODING, buf, len);
|
||||
if (!cc) {
|
||||
cryptoapi_report_error("CryptCreateCertificateContext");
|
||||
os_free(pk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
|
||||
0)) {
|
||||
cryptoapi_report_error("CryptAcquireContext");
|
||||
os_free(pk);
|
||||
CertFreeCertificateContext(cc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
|
||||
PKCS_7_ASN_ENCODING,
|
||||
&cc->pCertInfo->SubjectPublicKeyInfo,
|
||||
&pk->rsa)) {
|
||||
cryptoapi_report_error("CryptImportPublicKeyInfo");
|
||||
CryptReleaseContext(pk->prov, 0);
|
||||
os_free(pk);
|
||||
CertFreeCertificateContext(cc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CertFreeCertificateContext(cc);
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
||||
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
|
||||
const u8 *in, size_t inlen,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
DWORD clen;
|
||||
u8 *tmp;
|
||||
size_t i;
|
||||
|
||||
if (*outlen < inlen)
|
||||
return -1;
|
||||
tmp = malloc(*outlen);
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
|
||||
os_memcpy(tmp, in, inlen);
|
||||
clen = inlen;
|
||||
if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
|
||||
wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
|
||||
"public key: %d", (int) GetLastError());
|
||||
os_free(tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*outlen = clen;
|
||||
|
||||
/* Reverse the output */
|
||||
for (i = 0; i < *outlen; i++)
|
||||
out[i] = tmp[*outlen - 1 - i];
|
||||
|
||||
os_free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
|
||||
const u8 *in, size_t inlen,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
/* TODO */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void crypto_public_key_free(struct crypto_public_key *key)
|
||||
{
|
||||
if (key) {
|
||||
CryptDestroyKey(key->rsa);
|
||||
CryptReleaseContext(key->prov, 0);
|
||||
os_free(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void crypto_private_key_free(struct crypto_private_key *key)
|
||||
{
|
||||
if (key) {
|
||||
CryptDestroyKey(key->rsa);
|
||||
CryptReleaseContext(key->prov, 0);
|
||||
os_free(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int crypto_global_init(void)
|
||||
{
|
||||
return mingw_load_crypto_func();
|
||||
}
|
||||
|
||||
|
||||
void crypto_global_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
const u8 *power, size_t power_len,
|
||||
const u8 *modulus, size_t modulus_len,
|
||||
u8 *result, size_t *result_len)
|
||||
{
|
||||
/* TODO */
|
||||
return -1;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Crypto wrapper for internal crypto implementation - modexp
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "tls/bignum.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
const u8 *power, size_t power_len,
|
||||
const u8 *modulus, size_t modulus_len,
|
||||
u8 *result, size_t *result_len)
|
||||
{
|
||||
struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
|
||||
int ret = -1;
|
||||
|
||||
bn_base = bignum_init();
|
||||
bn_exp = bignum_init();
|
||||
bn_modulus = bignum_init();
|
||||
bn_result = bignum_init();
|
||||
|
||||
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
|
||||
bn_result == NULL)
|
||||
goto error;
|
||||
|
||||
if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
|
||||
bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
|
||||
bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
|
||||
goto error;
|
||||
|
||||
if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
|
||||
goto error;
|
||||
|
||||
ret = bignum_get_unsigned_bin(bn_result, result, result_len);
|
||||
|
||||
error:
|
||||
bignum_deinit(bn_base);
|
||||
bignum_deinit(bn_exp);
|
||||
bignum_deinit(bn_modulus);
|
||||
bignum_deinit(bn_result);
|
||||
return ret;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant / Empty template functions for crypto wrapper
|
||||
* 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 "crypto.h"
|
||||
|
||||
|
||||
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
{
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* Crypto wrapper functions for NSS
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <nspr/prtypes.h>
|
||||
#include <nspr/plarenas.h>
|
||||
#include <nspr/plhash.h>
|
||||
#include <nspr/prtime.h>
|
||||
#include <nspr/prinrval.h>
|
||||
#include <nspr/prclist.h>
|
||||
#include <nspr/prlock.h>
|
||||
#include <nss/sechash.h>
|
||||
#include <nss/pk11pub.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
static int nss_hash(HASH_HashType type, unsigned int max_res_len,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac)
|
||||
{
|
||||
HASHContext *ctx;
|
||||
size_t i;
|
||||
unsigned int reslen;
|
||||
|
||||
ctx = HASH_Create(type);
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
|
||||
HASH_Begin(ctx);
|
||||
for (i = 0; i < num_elem; i++)
|
||||
HASH_Update(ctx, addr[i], len[i]);
|
||||
HASH_End(ctx, mac, &reslen, max_res_len);
|
||||
HASH_Destroy(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
{
|
||||
PK11Context *ctx = NULL;
|
||||
PK11SlotInfo *slot;
|
||||
SECItem *param = NULL;
|
||||
PK11SymKey *symkey = NULL;
|
||||
SECItem item;
|
||||
int olen;
|
||||
u8 pkey[8], next, tmp;
|
||||
int i;
|
||||
|
||||
/* Add parity bits to the key */
|
||||
next = 0;
|
||||
for (i = 0; i < 7; i++) {
|
||||
tmp = key[i];
|
||||
pkey[i] = (tmp >> i) | next | 1;
|
||||
next = tmp << (7 - i);
|
||||
}
|
||||
pkey[i] = next | 1;
|
||||
|
||||
slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
|
||||
if (slot == NULL) {
|
||||
wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
item.type = siBuffer;
|
||||
item.data = pkey;
|
||||
item.len = 8;
|
||||
symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
|
||||
CKA_ENCRYPT, &item, NULL);
|
||||
if (symkey == NULL) {
|
||||
wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
|
||||
if (param == NULL) {
|
||||
wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
|
||||
symkey, param);
|
||||
if (ctx == NULL) {
|
||||
wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
|
||||
"CKM_DES_ECB) failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
|
||||
SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ctx)
|
||||
PK11_DestroyContext(ctx, PR_TRUE);
|
||||
if (symkey)
|
||||
PK11_FreeSymKey(symkey);
|
||||
if (param)
|
||||
SECITEM_FreeItem(param, PR_TRUE);
|
||||
}
|
||||
|
||||
|
||||
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac)
|
||||
{
|
||||
return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
void * aes_encrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt_deinit(void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void * aes_decrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt_deinit(void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
const u8 *power, size_t power_len,
|
||||
const u8 *modulus, size_t modulus_len,
|
||||
u8 *result, size_t *result_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_cipher {
|
||||
};
|
||||
|
||||
|
||||
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
|
||||
const u8 *iv, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
|
||||
u8 *crypt, size_t len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
|
||||
u8 *plain, size_t len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void crypto_cipher_deinit(struct crypto_cipher *ctx)
|
||||
{
|
||||
}
|
|
@ -1,505 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant / wrapper functions for libcrypto
|
||||
* 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 <openssl/opensslv.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "wpabuf.h"
|
||||
#include "dh_group5.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00907000
|
||||
#define DES_key_schedule des_key_schedule
|
||||
#define DES_cblock des_cblock
|
||||
#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
|
||||
#define DES_ecb_encrypt(input, output, ks, enc) \
|
||||
des_ecb_encrypt((input), (output), *(ks), (enc))
|
||||
#endif /* openssl < 0.9.7 */
|
||||
|
||||
static BIGNUM * get_group5_prime(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00908000
|
||||
static const unsigned char RFC3526_PRIME_1536[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
|
||||
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
|
||||
0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
|
||||
0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
||||
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
|
||||
0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
|
||||
0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
|
||||
0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
||||
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
|
||||
0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
|
||||
0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
|
||||
0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
||||
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
|
||||
0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
|
||||
0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
|
||||
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
};
|
||||
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
|
||||
#else /* openssl < 0.9.8 */
|
||||
return get_rfc3526_prime_1536(NULL);
|
||||
#endif /* openssl < 0.9.8 */
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00908000
|
||||
#ifndef OPENSSL_NO_SHA256
|
||||
#ifndef OPENSSL_FIPS
|
||||
#define NO_SHA256_WRAPPER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* openssl < 0.9.8 */
|
||||
|
||||
#ifdef OPENSSL_NO_SHA256
|
||||
#define NO_SHA256_WRAPPER
|
||||
#endif
|
||||
|
||||
static int openssl_digest_vector(const EVP_MD *type, int non_fips,
|
||||
size_t num_elem, const u8 *addr[],
|
||||
const size_t *len, u8 *mac)
|
||||
{
|
||||
EVP_MD_CTX ctx;
|
||||
size_t i;
|
||||
unsigned int mac_len;
|
||||
|
||||
EVP_MD_CTX_init(&ctx);
|
||||
#ifdef CONFIG_FIPS
|
||||
#ifdef OPENSSL_FIPS
|
||||
if (non_fips)
|
||||
EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
|
||||
#endif /* OPENSSL_FIPS */
|
||||
#endif /* CONFIG_FIPS */
|
||||
if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
|
||||
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
|
||||
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
|
||||
"failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
|
||||
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
{
|
||||
u8 pkey[8], next, tmp;
|
||||
int i;
|
||||
DES_key_schedule ks;
|
||||
|
||||
/* Add parity bits to the key */
|
||||
next = 0;
|
||||
for (i = 0; i < 7; i++) {
|
||||
tmp = key[i];
|
||||
pkey[i] = (tmp >> i) | next | 1;
|
||||
next = tmp << (7 - i);
|
||||
}
|
||||
pkey[i] = next | 1;
|
||||
|
||||
DES_set_key(&pkey, &ks);
|
||||
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
|
||||
DES_ENCRYPT);
|
||||
}
|
||||
|
||||
|
||||
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len)
|
||||
{
|
||||
#ifdef OPENSSL_NO_RC4
|
||||
return -1;
|
||||
#else /* OPENSSL_NO_RC4 */
|
||||
EVP_CIPHER_CTX ctx;
|
||||
int outl;
|
||||
int res = -1;
|
||||
unsigned char skip_buf[16];
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
|
||||
!EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
|
||||
!EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
|
||||
!EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
|
||||
goto out;
|
||||
|
||||
while (skip >= sizeof(skip_buf)) {
|
||||
size_t len = skip;
|
||||
if (len > sizeof(skip_buf))
|
||||
len = sizeof(skip_buf);
|
||||
if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
|
||||
goto out;
|
||||
skip -= len;
|
||||
}
|
||||
|
||||
if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return res;
|
||||
#endif /* OPENSSL_NO_RC4 */
|
||||
}
|
||||
|
||||
|
||||
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FIPS
|
||||
int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
|
||||
const size_t *len, u8 *mac)
|
||||
{
|
||||
return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
|
||||
}
|
||||
#endif /* CONFIG_FIPS */
|
||||
|
||||
|
||||
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_SHA256_WRAPPER
|
||||
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *mac)
|
||||
{
|
||||
return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
|
||||
mac);
|
||||
}
|
||||
#endif /* NO_SHA256_WRAPPER */
|
||||
|
||||
|
||||
void * aes_encrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
AES_KEY *ak;
|
||||
ak = os_malloc(sizeof(*ak));
|
||||
if (ak == NULL)
|
||||
return NULL;
|
||||
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
|
||||
os_free(ak);
|
||||
return NULL;
|
||||
}
|
||||
return ak;
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
|
||||
{
|
||||
AES_encrypt(plain, crypt, ctx);
|
||||
}
|
||||
|
||||
|
||||
void aes_encrypt_deinit(void *ctx)
|
||||
{
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
void * aes_decrypt_init(const u8 *key, size_t len)
|
||||
{
|
||||
AES_KEY *ak;
|
||||
ak = os_malloc(sizeof(*ak));
|
||||
if (ak == NULL)
|
||||
return NULL;
|
||||
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
|
||||
os_free(ak);
|
||||
return NULL;
|
||||
}
|
||||
return ak;
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
|
||||
{
|
||||
AES_decrypt(crypt, plain, ctx);
|
||||
}
|
||||
|
||||
|
||||
void aes_decrypt_deinit(void *ctx)
|
||||
{
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
int crypto_mod_exp(const u8 *base, size_t base_len,
|
||||
const u8 *power, size_t power_len,
|
||||
const u8 *modulus, size_t modulus_len,
|
||||
u8 *result, size_t *result_len)
|
||||
{
|
||||
BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
|
||||
int ret = -1;
|
||||
BN_CTX *ctx;
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
|
||||
bn_base = BN_bin2bn(base, base_len, NULL);
|
||||
bn_exp = BN_bin2bn(power, power_len, NULL);
|
||||
bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
|
||||
bn_result = BN_new();
|
||||
|
||||
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
|
||||
bn_result == NULL)
|
||||
goto error;
|
||||
|
||||
if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
|
||||
goto error;
|
||||
|
||||
*result_len = BN_bn2bin(bn_result, result);
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
BN_free(bn_base);
|
||||
BN_free(bn_exp);
|
||||
BN_free(bn_modulus);
|
||||
BN_free(bn_result);
|
||||
BN_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_cipher {
|
||||
EVP_CIPHER_CTX enc;
|
||||
EVP_CIPHER_CTX dec;
|
||||
};
|
||||
|
||||
|
||||
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
|
||||
const u8 *iv, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct crypto_cipher *ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
|
||||
ctx = os_zalloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
switch (alg) {
|
||||
#ifndef OPENSSL_NO_RC4
|
||||
case CRYPTO_CIPHER_ALG_RC4:
|
||||
cipher = EVP_rc4();
|
||||
break;
|
||||
#endif /* OPENSSL_NO_RC4 */
|
||||
#ifndef OPENSSL_NO_AES
|
||||
case CRYPTO_CIPHER_ALG_AES:
|
||||
switch (key_len) {
|
||||
case 16:
|
||||
cipher = EVP_aes_128_cbc();
|
||||
break;
|
||||
case 24:
|
||||
cipher = EVP_aes_192_cbc();
|
||||
break;
|
||||
case 32:
|
||||
cipher = EVP_aes_256_cbc();
|
||||
break;
|
||||
default:
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
#endif /* OPENSSL_NO_AES */
|
||||
#ifndef OPENSSL_NO_DES
|
||||
case CRYPTO_CIPHER_ALG_3DES:
|
||||
cipher = EVP_des_ede3_cbc();
|
||||
break;
|
||||
case CRYPTO_CIPHER_ALG_DES:
|
||||
cipher = EVP_des_cbc();
|
||||
break;
|
||||
#endif /* OPENSSL_NO_DES */
|
||||
#ifndef OPENSSL_NO_RC2
|
||||
case CRYPTO_CIPHER_ALG_RC2:
|
||||
cipher = EVP_rc2_ecb();
|
||||
break;
|
||||
#endif /* OPENSSL_NO_RC2 */
|
||||
default:
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx->enc);
|
||||
EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
|
||||
if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
|
||||
!EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
|
||||
!EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
|
||||
EVP_CIPHER_CTX_cleanup(&ctx->enc);
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx->dec);
|
||||
EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
|
||||
if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
|
||||
!EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
|
||||
!EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
|
||||
EVP_CIPHER_CTX_cleanup(&ctx->enc);
|
||||
EVP_CIPHER_CTX_cleanup(&ctx->dec);
|
||||
os_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
|
||||
u8 *crypt, size_t len)
|
||||
{
|
||||
int outl;
|
||||
if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
|
||||
u8 *plain, size_t len)
|
||||
{
|
||||
int outl;
|
||||
outl = len;
|
||||
if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void crypto_cipher_deinit(struct crypto_cipher *ctx)
|
||||
{
|
||||
EVP_CIPHER_CTX_cleanup(&ctx->enc);
|
||||
EVP_CIPHER_CTX_cleanup(&ctx->dec);
|
||||
os_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
|
||||
{
|
||||
DH *dh;
|
||||
struct wpabuf *pubkey = NULL, *privkey = NULL;
|
||||
size_t publen, privlen;
|
||||
|
||||
*priv = NULL;
|
||||
*publ = NULL;
|
||||
|
||||
dh = DH_new();
|
||||
if (dh == NULL)
|
||||
return NULL;
|
||||
|
||||
dh->g = BN_new();
|
||||
if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
|
||||
goto err;
|
||||
|
||||
dh->p = get_group5_prime();
|
||||
if (dh->p == NULL)
|
||||
goto err;
|
||||
|
||||
if (DH_generate_key(dh) != 1)
|
||||
goto err;
|
||||
|
||||
publen = BN_num_bytes(dh->pub_key);
|
||||
pubkey = wpabuf_alloc(publen);
|
||||
if (pubkey == NULL)
|
||||
goto err;
|
||||
privlen = BN_num_bytes(dh->priv_key);
|
||||
privkey = wpabuf_alloc(privlen);
|
||||
if (privkey == NULL)
|
||||
goto err;
|
||||
|
||||
BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
|
||||
BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
|
||||
|
||||
*priv = privkey;
|
||||
*publ = pubkey;
|
||||
return dh;
|
||||
|
||||
err:
|
||||
wpabuf_free(pubkey);
|
||||
wpabuf_free(privkey);
|
||||
DH_free(dh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
|
||||
const struct wpabuf *own_private)
|
||||
{
|
||||
BIGNUM *pub_key;
|
||||
struct wpabuf *res = NULL;
|
||||
size_t rlen;
|
||||
DH *dh = ctx;
|
||||
int keylen;
|
||||
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
|
||||
NULL);
|
||||
if (pub_key == NULL)
|
||||
return NULL;
|
||||
|
||||
rlen = DH_size(dh);
|
||||
res = wpabuf_alloc(rlen);
|
||||
if (res == NULL)
|
||||
goto err;
|
||||
|
||||
keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
|
||||
if (keylen < 0)
|
||||
goto err;
|
||||
wpabuf_put(res, keylen);
|
||||
BN_free(pub_key);
|
||||
|
||||
return res;
|
||||
|
||||
err:
|
||||
BN_free(pub_key);
|
||||
wpabuf_free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void dh5_free(void *ctx)
|
||||
{
|
||||
DH *dh;
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
dh = ctx;
|
||||
DH_free(dh);
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Diffie-Hellman group 5 operations
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef DH_GROUP5_H
|
||||
#define DH_GROUP5_H
|
||||
|
||||
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
|
||||
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
|
||||
const struct wpabuf *own_private);
|
||||
void dh5_free(void *ctx);
|
||||
|
||||
#endif /* DH_GROUP5_H */
|
|
@ -1,633 +0,0 @@
|
|||
/*
|
||||
* Diffie-Hellman groups
|
||||
* 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"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
#include "random.h"
|
||||
#include "dh_groups.h"
|
||||
|
||||
|
||||
#ifdef ALL_DH_GROUPS
|
||||
|
||||
/* RFC 4306, B.1. Group 1 - 768 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
|
||||
*/
|
||||
static const u8 dh_group1_generator[1] = { 0x02 };
|
||||
static const u8 dh_group1_prime[96] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
|
||||
*/
|
||||
static const u8 dh_group2_generator[1] = { 0x02 };
|
||||
static const u8 dh_group2_prime[128] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
|
||||
/* RFC 3526, 2. Group 5 - 1536 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
|
||||
*/
|
||||
static const u8 dh_group5_generator[1] = { 0x02 };
|
||||
static const u8 dh_group5_prime[192] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#ifdef ALL_DH_GROUPS
|
||||
|
||||
/* RFC 3526, 3. Group 14 - 2048 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
|
||||
*/
|
||||
static const u8 dh_group14_generator[1] = { 0x02 };
|
||||
static const u8 dh_group14_prime[256] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
|
||||
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
|
||||
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
|
||||
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* RFC 3526, 4. Group 15 - 3072 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
|
||||
*/
|
||||
static const u8 dh_group15_generator[1] = { 0x02 };
|
||||
static const u8 dh_group15_prime[384] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
|
||||
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
|
||||
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
|
||||
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
|
||||
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
|
||||
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
||||
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
|
||||
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
|
||||
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
||||
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
|
||||
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
|
||||
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
||||
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
|
||||
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
|
||||
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
||||
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
|
||||
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
|
||||
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
||||
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
|
||||
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* RFC 3526, 5. Group 16 - 4096 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
|
||||
*/
|
||||
static const u8 dh_group16_generator[1] = { 0x02 };
|
||||
static const u8 dh_group16_prime[512] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
|
||||
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
|
||||
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
|
||||
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
|
||||
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
|
||||
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
||||
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
|
||||
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
|
||||
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
||||
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
|
||||
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
|
||||
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
||||
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
|
||||
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
|
||||
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
||||
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
|
||||
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
|
||||
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
||||
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
|
||||
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
|
||||
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
|
||||
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
|
||||
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
|
||||
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
|
||||
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
|
||||
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
|
||||
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
|
||||
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
|
||||
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
|
||||
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
|
||||
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
|
||||
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
|
||||
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
|
||||
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
|
||||
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
|
||||
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* RFC 3526, 6. Group 17 - 6144 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
|
||||
*/
|
||||
static const u8 dh_group17_generator[1] = { 0x02 };
|
||||
static const u8 dh_group17_prime[768] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
|
||||
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
|
||||
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
|
||||
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
|
||||
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
|
||||
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
||||
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
|
||||
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
|
||||
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
||||
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
|
||||
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
|
||||
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
||||
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
|
||||
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
|
||||
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
||||
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
|
||||
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
|
||||
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
||||
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
|
||||
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
|
||||
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
|
||||
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
|
||||
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
|
||||
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
|
||||
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
|
||||
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
|
||||
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
|
||||
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
|
||||
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
|
||||
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
|
||||
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
|
||||
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
|
||||
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
|
||||
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
|
||||
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
|
||||
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
|
||||
0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
|
||||
0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
|
||||
0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
|
||||
0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
|
||||
0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
|
||||
0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
|
||||
0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
|
||||
0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
|
||||
0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
|
||||
0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
|
||||
0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
|
||||
0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
|
||||
0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
|
||||
0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
|
||||
0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
|
||||
0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
|
||||
0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
|
||||
0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
|
||||
0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
|
||||
0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
|
||||
0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
|
||||
0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
|
||||
0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
|
||||
0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
|
||||
0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
|
||||
0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
|
||||
0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
|
||||
0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
|
||||
0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
|
||||
0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
|
||||
0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
|
||||
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
/* RFC 3526, 7. Group 18 - 8192 Bit MODP
|
||||
* Generator: 2
|
||||
* Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
|
||||
*/
|
||||
static const u8 dh_group18_generator[1] = { 0x02 };
|
||||
static const u8 dh_group18_prime[1024] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
|
||||
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
|
||||
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
|
||||
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
|
||||
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
|
||||
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
|
||||
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
|
||||
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
|
||||
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
|
||||
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
|
||||
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
|
||||
0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
|
||||
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
|
||||
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
|
||||
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
|
||||
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
|
||||
0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
|
||||
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
|
||||
0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
|
||||
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
|
||||
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
|
||||
0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
|
||||
0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
|
||||
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
|
||||
0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
|
||||
0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
|
||||
0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
|
||||
0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
|
||||
0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
|
||||
0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
|
||||
0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
|
||||
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
|
||||
0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
|
||||
0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
|
||||
0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
|
||||
0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
|
||||
0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
|
||||
0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
|
||||
0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
|
||||
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
|
||||
0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
|
||||
0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
|
||||
0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
|
||||
0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
|
||||
0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
|
||||
0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
|
||||
0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
|
||||
0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
|
||||
0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
|
||||
0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
|
||||
0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
|
||||
0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
|
||||
0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
|
||||
0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
|
||||
0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
|
||||
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
|
||||
0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
|
||||
0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
|
||||
0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
|
||||
0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
|
||||
0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
|
||||
0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
|
||||
0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
|
||||
0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
|
||||
0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
|
||||
0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
|
||||
0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
|
||||
0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
|
||||
0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
|
||||
0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
|
||||
0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
|
||||
0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
|
||||
0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
|
||||
0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
|
||||
0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
|
||||
0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
|
||||
0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
|
||||
0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
|
||||
0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
|
||||
0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
|
||||
0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
|
||||
0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
|
||||
0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
|
||||
0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
|
||||
0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
|
||||
0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
|
||||
0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
|
||||
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
|
||||
0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
|
||||
0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
|
||||
0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
|
||||
0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
|
||||
0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
|
||||
0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
|
||||
0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
|
||||
0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
|
||||
0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
|
||||
0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
|
||||
0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
|
||||
0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
|
||||
0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
|
||||
0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
|
||||
0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
|
||||
0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
|
||||
0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
|
||||
0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
|
||||
0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
|
||||
0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
|
||||
0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
|
||||
0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
|
||||
0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
|
||||
0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
|
||||
0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
|
||||
0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
|
||||
0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
|
||||
0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
|
||||
0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
|
||||
0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
|
||||
0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
|
||||
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
|
||||
|
||||
#define DH_GROUP(id) \
|
||||
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
|
||||
dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
|
||||
|
||||
|
||||
static struct dh_group dh_groups[] = {
|
||||
DH_GROUP(5),
|
||||
#ifdef ALL_DH_GROUPS
|
||||
DH_GROUP(1),
|
||||
DH_GROUP(2),
|
||||
DH_GROUP(14),
|
||||
DH_GROUP(15),
|
||||
DH_GROUP(16),
|
||||
DH_GROUP(17),
|
||||
DH_GROUP(18)
|
||||
#endif /* ALL_DH_GROUPS */
|
||||
};
|
||||
|
||||
#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
|
||||
|
||||
|
||||
const struct dh_group * dh_groups_get(int id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NUM_DH_GROUPS; i++) {
|
||||
if (dh_groups[i].id == id)
|
||||
return &dh_groups[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dh_init - Initialize Diffie-Hellman handshake
|
||||
* @dh: Selected Diffie-Hellman group
|
||||
* @priv: Pointer for returning Diffie-Hellman private key
|
||||
* Returns: Diffie-Hellman public value
|
||||
*/
|
||||
struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
|
||||
{
|
||||
struct wpabuf *pv;
|
||||
size_t pv_len;
|
||||
|
||||
if (dh == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_free(*priv);
|
||||
*priv = wpabuf_alloc(dh->prime_len);
|
||||
if (*priv == NULL)
|
||||
return NULL;
|
||||
|
||||
if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
|
||||
{
|
||||
wpabuf_free(*priv);
|
||||
*priv = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
|
||||
/* Make sure private value is smaller than prime */
|
||||
*(wpabuf_mhead_u8(*priv)) = 0;
|
||||
}
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
|
||||
|
||||
pv_len = dh->prime_len;
|
||||
pv = wpabuf_alloc(pv_len);
|
||||
if (pv == NULL)
|
||||
return NULL;
|
||||
if (crypto_mod_exp(dh->generator, dh->generator_len,
|
||||
wpabuf_head(*priv), wpabuf_len(*priv),
|
||||
dh->prime, dh->prime_len, wpabuf_mhead(pv),
|
||||
&pv_len) < 0) {
|
||||
wpabuf_free(pv);
|
||||
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(pv, pv_len);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dh_derive_shared - Derive shared Diffie-Hellman key
|
||||
* @peer_public: Diffie-Hellman public value from peer
|
||||
* @own_private: Diffie-Hellman private key from dh_init()
|
||||
* @dh: Selected Diffie-Hellman group
|
||||
* Returns: Diffie-Hellman shared key
|
||||
*/
|
||||
struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
|
||||
const struct wpabuf *own_private,
|
||||
const struct dh_group *dh)
|
||||
{
|
||||
struct wpabuf *shared;
|
||||
size_t shared_len;
|
||||
|
||||
if (dh == NULL || peer_public == NULL || own_private == NULL)
|
||||
return NULL;
|
||||
|
||||
shared_len = dh->prime_len;
|
||||
shared = wpabuf_alloc(shared_len);
|
||||
if (shared == NULL)
|
||||
return NULL;
|
||||
if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
|
||||
wpabuf_head(own_private), wpabuf_len(own_private),
|
||||
dh->prime, dh->prime_len,
|
||||
wpabuf_mhead(shared), &shared_len) < 0) {
|
||||
wpabuf_free(shared);
|
||||
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(shared, shared_len);
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
|
||||
|
||||
return shared;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* FIPS 186-2 PRF for Microsoft CryptoAPI
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
|
||||
{
|
||||
/* FIX: how to do this with CryptoAPI? */
|
||||
return -1;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* FIPS 186-2 PRF for libgcrypt
|
||||
* 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 <gcrypt.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
|
||||
{
|
||||
/* FIX: how to do this with libgcrypt? */
|
||||
return -1;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* FIPS 186-2 PRF for NSS
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
|
||||
{
|
||||
return -1;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* FIPS 186-2 PRF for libcrypto
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
static void sha1_transform(u8 *state, const u8 data[64])
|
||||
{
|
||||
SHA_CTX context;
|
||||
os_memset(&context, 0, sizeof(context));
|
||||
os_memcpy(&context.h0, state, 5 * 4);
|
||||
SHA1_Transform(&context, data);
|
||||
os_memcpy(state, &context.h0, 5 * 4);
|
||||
}
|
||||
|
||||
|
||||
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
|
||||
{
|
||||
u8 xkey[64];
|
||||
u32 t[5], _t[5];
|
||||
int i, j, m, k;
|
||||
u8 *xpos = x;
|
||||
u32 carry;
|
||||
|
||||
if (seed_len > sizeof(xkey))
|
||||
seed_len = sizeof(xkey);
|
||||
|
||||
/* FIPS 186-2 + change notice 1 */
|
||||
|
||||
os_memcpy(xkey, seed, seed_len);
|
||||
os_memset(xkey + seed_len, 0, 64 - seed_len);
|
||||
t[0] = 0x67452301;
|
||||
t[1] = 0xEFCDAB89;
|
||||
t[2] = 0x98BADCFE;
|
||||
t[3] = 0x10325476;
|
||||
t[4] = 0xC3D2E1F0;
|
||||
|
||||
m = xlen / 40;
|
||||
for (j = 0; j < m; j++) {
|
||||
/* XSEED_j = 0 */
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* XVAL = (XKEY + XSEED_j) mod 2^b */
|
||||
|
||||
/* w_i = G(t, XVAL) */
|
||||
os_memcpy(_t, t, 20);
|
||||
sha1_transform((u8 *) _t, xkey);
|
||||
_t[0] = host_to_be32(_t[0]);
|
||||
_t[1] = host_to_be32(_t[1]);
|
||||
_t[2] = host_to_be32(_t[2]);
|
||||
_t[3] = host_to_be32(_t[3]);
|
||||
_t[4] = host_to_be32(_t[4]);
|
||||
os_memcpy(xpos, _t, 20);
|
||||
|
||||
/* XKEY = (1 + XKEY + w_i) mod 2^b */
|
||||
carry = 1;
|
||||
for (k = 19; k >= 0; k--) {
|
||||
carry += xkey[k] + xpos[k];
|
||||
xkey[k] = carry & 0xff;
|
||||
carry >>= 8;
|
||||
}
|
||||
|
||||
xpos += 20;
|
||||
}
|
||||
/* x_j = w_0|w_1 */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* MD5 hash implementation and interface functions (non-FIPS allowed cases)
|
||||
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "md5.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
/**
|
||||
* hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @num_elem: Number of elements in the data vector
|
||||
* @addr: Pointers to the data areas
|
||||
* @len: Lengths of the data blocks
|
||||
* @mac: Buffer for the hash (16 bytes)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
|
||||
size_t num_elem, const u8 *addr[],
|
||||
const size_t *len, u8 *mac)
|
||||
{
|
||||
u8 k_pad[64]; /* padding - key XORd with ipad/opad */
|
||||
u8 tk[16];
|
||||
const u8 *_addr[6];
|
||||
size_t i, _len[6];
|
||||
|
||||
if (num_elem > 5) {
|
||||
/*
|
||||
* Fixed limit on the number of fragments to avoid having to
|
||||
* allocate memory (which could fail).
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if key is longer than 64 bytes reset it to key = MD5(key) */
|
||||
if (key_len > 64) {
|
||||
if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
|
||||
return -1;
|
||||
key = tk;
|
||||
key_len = 16;
|
||||
}
|
||||
|
||||
/* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected */
|
||||
|
||||
/* start out by storing key in ipad */
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
|
||||
/* XOR key with ipad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x36;
|
||||
|
||||
/* perform inner MD5 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
_addr[i + 1] = addr[i];
|
||||
_len[i + 1] = len[i];
|
||||
}
|
||||
if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
|
||||
return -1;
|
||||
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
/* XOR key with opad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x5c;
|
||||
|
||||
/* perform outer MD5 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
_addr[1] = mac;
|
||||
_len[1] = MD5_MAC_LEN;
|
||||
return md5_vector_non_fips_allow(2, _addr, _len, mac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @data: Pointers to the data area
|
||||
* @data_len: Length of the data area
|
||||
* @mac: Buffer for the hash (16 bytes)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac)
|
||||
{
|
||||
return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
|
||||
&data_len, mac);
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* MD5 hash implementation and interface functions
|
||||
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
#define MD5_MAC_LEN 16
|
||||
|
||||
int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac);
|
||||
int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
|
||||
u8 *mac);
|
||||
#ifdef CONFIG_FIPS
|
||||
int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
|
||||
size_t num_elem, const u8 *addr[],
|
||||
const size_t *len, u8 *mac);
|
||||
int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac);
|
||||
#else /* CONFIG_FIPS */
|
||||
#define hmac_md5_vector_non_fips_allow hmac_md5_vector
|
||||
#define hmac_md5_non_fips_allow hmac_md5
|
||||
#endif /* CONFIG_FIPS */
|
||||
|
||||
#endif /* MD5_H */
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* SHA-256 hash implementation and interface functions
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "sha256.h"
|
||||
#include "crypto.h"
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @num_elem: Number of elements in the data vector
|
||||
* @addr: Pointers to the data areas
|
||||
* @len: Lengths of the data blocks
|
||||
* @mac: Buffer for the hash (32 bytes)
|
||||
*/
|
||||
void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
|
||||
unsigned char tk[32];
|
||||
const u8 *_addr[6];
|
||||
size_t _len[6], i;
|
||||
|
||||
if (num_elem > 5) {
|
||||
/*
|
||||
* Fixed limit on the number of fragments to avoid having to
|
||||
* allocate memory (which could fail).
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* if key is longer than 64 bytes reset it to key = SHA256(key) */
|
||||
if (key_len > 64) {
|
||||
sha256_vector(1, &key, &key_len, tk);
|
||||
key = tk;
|
||||
key_len = 32;
|
||||
}
|
||||
|
||||
/* the HMAC_SHA256 transform looks like:
|
||||
*
|
||||
* SHA256(K XOR opad, SHA256(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected */
|
||||
|
||||
/* start out by storing key in ipad */
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
/* XOR key with ipad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x36;
|
||||
|
||||
/* perform inner SHA256 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
_addr[i + 1] = addr[i];
|
||||
_len[i + 1] = len[i];
|
||||
}
|
||||
sha256_vector(1 + num_elem, _addr, _len, mac);
|
||||
|
||||
os_memset(k_pad, 0, sizeof(k_pad));
|
||||
os_memcpy(k_pad, key, key_len);
|
||||
/* XOR key with opad values */
|
||||
for (i = 0; i < 64; i++)
|
||||
k_pad[i] ^= 0x5c;
|
||||
|
||||
/* perform outer SHA256 */
|
||||
_addr[0] = k_pad;
|
||||
_len[0] = 64;
|
||||
_addr[1] = mac;
|
||||
_len[1] = SHA256_MAC_LEN;
|
||||
sha256_vector(2, _addr, _len, mac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
|
||||
* @key: Key for HMAC operations
|
||||
* @key_len: Length of the key in bytes
|
||||
* @data: Pointers to the data area
|
||||
* @data_len: Length of the data area
|
||||
* @mac: Buffer for the hash (20 bytes)
|
||||
*/
|
||||
void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac)
|
||||
{
|
||||
hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
|
||||
* @key: Key for PRF
|
||||
* @key_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @data: Extra data to bind into the key
|
||||
* @data_len: Length of the data
|
||||
* @buf: Buffer for the generated pseudo-random key
|
||||
* @buf_len: Number of bytes of key to generate
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key.
|
||||
*/
|
||||
void sha256_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
|
||||
{
|
||||
u16 counter = 1;
|
||||
size_t pos, plen;
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
u8 counter_le[2], length_le[2];
|
||||
|
||||
addr[0] = counter_le;
|
||||
len[0] = 2;
|
||||
addr[1] = (u8 *) label;
|
||||
len[1] = os_strlen(label);
|
||||
addr[2] = data;
|
||||
len[2] = data_len;
|
||||
addr[3] = length_le;
|
||||
len[3] = sizeof(length_le);
|
||||
|
||||
WPA_PUT_LE16(length_le, buf_len * 8);
|
||||
pos = 0;
|
||||
while (pos < buf_len) {
|
||||
plen = buf_len - pos;
|
||||
WPA_PUT_LE16(counter_le, counter);
|
||||
if (plen >= SHA256_MAC_LEN) {
|
||||
hmac_sha256_vector(key, key_len, 4, addr, len,
|
||||
&buf[pos]);
|
||||
pos += SHA256_MAC_LEN;
|
||||
} else {
|
||||
hmac_sha256_vector(key, key_len, 4, addr, len, hash);
|
||||
os_memcpy(&buf[pos], hash, plen);
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* SHA256 hash implementation and interface functions
|
||||
* Copyright (c) 2003-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 SHA256_H
|
||||
#define SHA256_H
|
||||
|
||||
#define SHA256_MAC_LEN 32
|
||||
|
||||
void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac);
|
||||
void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac);
|
||||
void sha256_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
|
||||
|
||||
#endif /* SHA256_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,680 +0,0 @@
|
|||
/*
|
||||
* SSL/TLS interface functions for NSS
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <nspr/prtypes.h>
|
||||
#include <nspr/plarenas.h>
|
||||
#include <nspr/plhash.h>
|
||||
#include <nspr/prio.h>
|
||||
#include <nspr/prclist.h>
|
||||
#include <nspr/prlock.h>
|
||||
#include <nspr/prinit.h>
|
||||
#include <nspr/prerror.h>
|
||||
#include <nspr/prmem.h>
|
||||
#include <nss/nss.h>
|
||||
#include <nss/nssilckt.h>
|
||||
#include <nss/ssl.h>
|
||||
#include <nss/pk11func.h>
|
||||
#include <nss/secerr.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tls.h"
|
||||
|
||||
static int tls_nss_ref_count = 0;
|
||||
|
||||
static PRDescIdentity nss_layer_id;
|
||||
|
||||
|
||||
struct tls_connection {
|
||||
PRFileDesc *fd;
|
||||
|
||||
int established;
|
||||
int verify_peer;
|
||||
u8 *push_buf, *pull_buf, *pull_buf_offset;
|
||||
size_t push_buf_len, pull_buf_len;
|
||||
};
|
||||
|
||||
|
||||
static PRStatus nss_io_close(PRFileDesc *fd)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O close");
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
|
||||
PRInt32 iov_size, PRIntervalTime timeout)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout)
|
||||
{
|
||||
struct tls_connection *conn = (struct tls_connection *) fd->secret;
|
||||
u8 *end;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
|
||||
|
||||
if (conn->pull_buf == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
end = conn->pull_buf + conn->pull_buf_len;
|
||||
if (end - conn->pull_buf_offset < amount)
|
||||
amount = end - conn->pull_buf_offset;
|
||||
os_memcpy(buf, conn->pull_buf_offset, amount);
|
||||
conn->pull_buf_offset += amount;
|
||||
if (conn->pull_buf_offset == end) {
|
||||
wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
|
||||
os_free(conn->pull_buf);
|
||||
conn->pull_buf = conn->pull_buf_offset = NULL;
|
||||
conn->pull_buf_len = 0;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
|
||||
__func__,
|
||||
(unsigned long) (end - conn->pull_buf_offset));
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRIntervalTime timeout)
|
||||
{
|
||||
struct tls_connection *conn = (struct tls_connection *) fd->secret;
|
||||
u8 *nbuf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
|
||||
wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
|
||||
|
||||
nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
|
||||
if (nbuf == NULL) {
|
||||
wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
|
||||
"data to be sent");
|
||||
return PR_FAILURE;
|
||||
}
|
||||
os_memcpy(nbuf + conn->push_buf_len, buf, amount);
|
||||
conn->push_buf = nbuf;
|
||||
conn->push_buf_len += amount;
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
|
||||
PRIntn flags, PRNetAddr *addr,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
|
||||
PRIntn flags, const PRNetAddr *addr,
|
||||
PRIntervalTime timeout)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
|
||||
|
||||
/*
|
||||
* It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
|
||||
* fake IPv4 address to work around this even though we are not really
|
||||
* using TCP.
|
||||
*/
|
||||
os_memset(addr, 0, sizeof(*addr));
|
||||
addr->inet.family = PR_AF_INET;
|
||||
|
||||
return PR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
|
||||
PRSocketOptionData *data)
|
||||
{
|
||||
switch (data->option) {
|
||||
case PR_SockOpt_Nonblocking:
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
|
||||
data->value.non_blocking = PR_TRUE;
|
||||
return PR_SUCCESS;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
|
||||
data->option);
|
||||
return PR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const PRIOMethods nss_io = {
|
||||
PR_DESC_LAYERED,
|
||||
nss_io_close,
|
||||
nss_io_read,
|
||||
nss_io_write,
|
||||
NULL /* available */,
|
||||
NULL /* available64 */,
|
||||
NULL /* fsync */,
|
||||
NULL /* fseek */,
|
||||
NULL /* fseek64 */,
|
||||
NULL /* fileinfo */,
|
||||
NULL /* fileinfo64 */,
|
||||
nss_io_writev,
|
||||
NULL /* connect */,
|
||||
NULL /* accept */,
|
||||
NULL /* bind */,
|
||||
NULL /* listen */,
|
||||
NULL /* shutdown */,
|
||||
nss_io_recv,
|
||||
nss_io_send,
|
||||
nss_io_recvfrom,
|
||||
nss_io_sendto,
|
||||
NULL /* poll */,
|
||||
NULL /* acceptread */,
|
||||
NULL /* transmitfile */,
|
||||
NULL /* getsockname */,
|
||||
nss_io_getpeername,
|
||||
NULL /* reserved_fn_6 */,
|
||||
NULL /* reserved_fn_5 */,
|
||||
nss_io_getsocketoption,
|
||||
NULL /* setsocketoption */,
|
||||
NULL /* sendfile */,
|
||||
NULL /* connectcontinue */,
|
||||
NULL /* reserved_fn_3 */,
|
||||
NULL /* reserved_fn_2 */,
|
||||
NULL /* reserved_fn_1 */,
|
||||
NULL /* reserved_fn_0 */
|
||||
};
|
||||
|
||||
|
||||
static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
|
||||
{
|
||||
wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void * tls_init(const struct tls_config *conf)
|
||||
{
|
||||
char *dir;
|
||||
|
||||
tls_nss_ref_count++;
|
||||
if (tls_nss_ref_count > 1)
|
||||
return (void *) 1;
|
||||
|
||||
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
|
||||
|
||||
nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
|
||||
|
||||
PK11_SetPasswordFunc(nss_password_cb);
|
||||
|
||||
dir = getenv("SSL_DIR");
|
||||
if (dir) {
|
||||
if (NSS_Init(dir) != SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
|
||||
"failed", dir);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (NSS_NoDB_Init(NULL) != SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
|
||||
SECSuccess ||
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
|
||||
SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (NSS_SetDomesticPolicy() != SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *) 1;
|
||||
}
|
||||
|
||||
void tls_deinit(void *ssl_ctx)
|
||||
{
|
||||
tls_nss_ref_count--;
|
||||
if (tls_nss_ref_count == 0) {
|
||||
if (NSS_Shutdown() != SECSuccess)
|
||||
wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int tls_get_errors(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
|
||||
{
|
||||
struct tls_connection *conn = arg;
|
||||
SECStatus res = SECSuccess;
|
||||
PRErrorCode err;
|
||||
CERTCertificate *cert;
|
||||
char *subject, *issuer;
|
||||
|
||||
err = PR_GetError();
|
||||
if (IS_SEC_ERROR(err))
|
||||
wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
|
||||
"%d)", err - SEC_ERROR_BASE);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
|
||||
err);
|
||||
cert = SSL_PeerCertificate(fd);
|
||||
subject = CERT_NameToAscii(&cert->subject);
|
||||
issuer = CERT_NameToAscii(&cert->issuer);
|
||||
wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
|
||||
subject, issuer);
|
||||
CERT_DestroyCertificate(cert);
|
||||
PR_Free(subject);
|
||||
PR_Free(issuer);
|
||||
if (conn->verify_peer)
|
||||
res = SECFailure;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
|
||||
{
|
||||
struct tls_connection *conn = client_data;
|
||||
wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
|
||||
conn->established = 1;
|
||||
}
|
||||
|
||||
|
||||
struct tls_connection * tls_connection_init(void *tls_ctx)
|
||||
{
|
||||
struct tls_connection *conn;
|
||||
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
|
||||
conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
|
||||
if (conn->fd == NULL) {
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
conn->fd->secret = (void *) conn;
|
||||
|
||||
conn->fd = SSL_ImportFD(NULL, conn->fd);
|
||||
if (conn->fd == NULL) {
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
|
||||
SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
|
||||
SECSuccess ||
|
||||
SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
|
||||
SECSuccess ||
|
||||
SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
|
||||
SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
|
||||
SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
|
||||
SECSuccess) {
|
||||
wpa_printf(MSG_ERROR, "NSS: Failed to set options");
|
||||
PR_Close(conn->fd);
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_ResetHandshake(conn->fd, PR_FALSE);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
PR_Close(conn->fd);
|
||||
os_free(conn->push_buf);
|
||||
os_free(conn->pull_buf);
|
||||
os_free(conn);
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return conn->established;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_params(void *tls_ctx,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
int verify_peer)
|
||||
{
|
||||
conn->verify_peer = verify_peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
|
||||
int tls_ia)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
|
||||
struct tls_keys *keys)
|
||||
{
|
||||
/* NSS does not export master secret or client/server random. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, int server_random_first,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
if (conn == NULL || server_random_first) {
|
||||
wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
|
||||
"(server_random_first=%d)",
|
||||
server_random_first);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
|
||||
SECSuccess) {
|
||||
wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
|
||||
"(label='%s' out_len=%d", label, (int) out_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
struct wpabuf *out_data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
|
||||
in_data ? (unsigned int) wpabuf_len(in_data) : 0);
|
||||
|
||||
if (appl_data)
|
||||
*appl_data = NULL;
|
||||
|
||||
if (in_data && wpabuf_len(in_data) > 0) {
|
||||
if (conn->pull_buf) {
|
||||
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
|
||||
"pull_buf", __func__,
|
||||
(unsigned long) conn->pull_buf_len);
|
||||
os_free(conn->pull_buf);
|
||||
}
|
||||
conn->pull_buf = os_malloc(wpabuf_len(in_data));
|
||||
if (conn->pull_buf == NULL)
|
||||
return NULL;
|
||||
os_memcpy(conn->pull_buf, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data));
|
||||
conn->pull_buf_offset = conn->pull_buf;
|
||||
conn->pull_buf_len = wpabuf_len(in_data);
|
||||
}
|
||||
|
||||
SSL_ForceHandshake(conn->fd);
|
||||
|
||||
if (conn->established && conn->push_buf == NULL) {
|
||||
/* Need to return something to get final TLS ACK. */
|
||||
conn->push_buf = os_malloc(1);
|
||||
}
|
||||
|
||||
if (conn->push_buf == NULL)
|
||||
return NULL;
|
||||
out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
|
||||
if (out_data == NULL)
|
||||
os_free(conn->push_buf);
|
||||
conn->push_buf = NULL;
|
||||
conn->push_buf_len = 0;
|
||||
return out_data;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
PRInt32 res;
|
||||
struct wpabuf *buf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
|
||||
(int) wpabuf_len(in_data));
|
||||
res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
|
||||
0);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "NSS: Encryption failed");
|
||||
return NULL;
|
||||
}
|
||||
if (conn->push_buf == NULL)
|
||||
return NULL;
|
||||
buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
|
||||
if (buf == NULL)
|
||||
os_free(conn->push_buf);
|
||||
conn->push_buf = NULL;
|
||||
conn->push_buf_len = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
PRInt32 res;
|
||||
struct wpabuf *out;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
|
||||
(int) wpabuf_len(in_data));
|
||||
if (conn->pull_buf) {
|
||||
wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
|
||||
"pull_buf", __func__,
|
||||
(unsigned long) conn->pull_buf_len);
|
||||
os_free(conn->pull_buf);
|
||||
}
|
||||
conn->pull_buf = os_malloc(wpabuf_len(in_data));
|
||||
if (conn->pull_buf == NULL)
|
||||
return NULL;
|
||||
os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
|
||||
conn->pull_buf_offset = conn->pull_buf;
|
||||
conn->pull_buf_len = wpabuf_len(in_data);
|
||||
|
||||
/*
|
||||
* Even though we try to disable TLS compression, it is possible that
|
||||
* this cannot be done with all TLS libraries. Add extra buffer space
|
||||
* to handle the possibility of the decrypted data being longer than
|
||||
* input data.
|
||||
*/
|
||||
out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
|
||||
wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
|
||||
if (res < 0) {
|
||||
wpabuf_free(out);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(out, res);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *ciphers)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_enable_workaround(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
|
||||
int ext_type, const u8 *data,
|
||||
size_t data_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_write_alerts(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_keyblock_size(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
unsigned int tls_capabilities(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_ia_send_phase_finished(
|
||||
void *tls_ctx, struct tls_connection *conn, int final)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_ia_final_phase_finished(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
tls_session_ticket_cb cb,
|
||||
void *ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,767 +0,0 @@
|
|||
/*
|
||||
* SSL/TLS interface functions for Microsoft Schannel
|
||||
* Copyright (c) 2005-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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIX: Go through all SSPI functions and verify what needs to be freed
|
||||
* FIX: session resumption
|
||||
* TODO: add support for server cert chain validation
|
||||
* TODO: add support for CA cert validation
|
||||
* TODO: add support for EAP-TLS (client cert/key conf)
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <schannel.h>
|
||||
#define SECURITY_WIN32
|
||||
#include <security.h>
|
||||
#include <sspi.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "tls.h"
|
||||
|
||||
|
||||
struct tls_global {
|
||||
HMODULE hsecurity;
|
||||
PSecurityFunctionTable sspi;
|
||||
HCERTSTORE my_cert_store;
|
||||
};
|
||||
|
||||
struct tls_connection {
|
||||
int established, start;
|
||||
int failed, read_alerts, write_alerts;
|
||||
|
||||
SCHANNEL_CRED schannel_cred;
|
||||
CredHandle creds;
|
||||
CtxtHandle context;
|
||||
|
||||
u8 eap_tls_prf[128];
|
||||
int eap_tls_prf_set;
|
||||
};
|
||||
|
||||
|
||||
static int schannel_load_lib(struct tls_global *global)
|
||||
{
|
||||
INIT_SECURITY_INTERFACE pInitSecurityInterface;
|
||||
|
||||
global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
|
||||
if (global->hsecurity == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
|
||||
__func__, (unsigned int) GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
|
||||
global->hsecurity, "InitSecurityInterfaceA");
|
||||
if (pInitSecurityInterface == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Could not find "
|
||||
"InitSecurityInterfaceA from Secur32.dll",
|
||||
__func__);
|
||||
FreeLibrary(global->hsecurity);
|
||||
global->hsecurity = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
global->sspi = pInitSecurityInterface();
|
||||
if (global->sspi == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Could not read security "
|
||||
"interface - 0x%x",
|
||||
__func__, (unsigned int) GetLastError());
|
||||
FreeLibrary(global->hsecurity);
|
||||
global->hsecurity = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * tls_init(const struct tls_config *conf)
|
||||
{
|
||||
struct tls_global *global;
|
||||
|
||||
global = os_zalloc(sizeof(*global));
|
||||
if (global == NULL)
|
||||
return NULL;
|
||||
if (schannel_load_lib(global)) {
|
||||
os_free(global);
|
||||
return NULL;
|
||||
}
|
||||
return global;
|
||||
}
|
||||
|
||||
|
||||
void tls_deinit(void *ssl_ctx)
|
||||
{
|
||||
struct tls_global *global = ssl_ctx;
|
||||
|
||||
if (global->my_cert_store)
|
||||
CertCloseStore(global->my_cert_store, 0);
|
||||
FreeLibrary(global->hsecurity);
|
||||
os_free(global);
|
||||
}
|
||||
|
||||
|
||||
int tls_get_errors(void *ssl_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct tls_connection * tls_connection_init(void *ssl_ctx)
|
||||
{
|
||||
struct tls_connection *conn;
|
||||
|
||||
conn = os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
conn->start = 1;
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return;
|
||||
|
||||
os_free(conn);
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return conn ? conn->established : 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
struct tls_global *global = ssl_ctx;
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
|
||||
conn->eap_tls_prf_set = 0;
|
||||
conn->established = conn->failed = 0;
|
||||
conn->read_alerts = conn->write_alerts = 0;
|
||||
global->sspi->DeleteSecurityContext(&conn->context);
|
||||
/* FIX: what else needs to be reseted? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_params(void *tls_ctx,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *ssl_ctx, int check_crl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
|
||||
int verify_peer)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
|
||||
struct tls_keys *keys)
|
||||
{
|
||||
/* Schannel does not export master secret or client/server random. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, int server_random_first,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
/*
|
||||
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
|
||||
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
|
||||
* EAP-TTLS cannot use this, though, since they are using different
|
||||
* labels. The only option could be to implement TLSv1 completely here
|
||||
* and just use Schannel or CryptoAPI for low-level crypto
|
||||
* functionality..
|
||||
*/
|
||||
|
||||
if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
|
||||
os_strcmp(label, "client EAP encryption") != 0 ||
|
||||
out_len > sizeof(conn->eap_tls_prf))
|
||||
return -1;
|
||||
|
||||
os_memcpy(out, conn->eap_tls_prf, out_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
DWORD sspi_flags, sspi_flags_out;
|
||||
SecBufferDesc outbuf;
|
||||
SecBuffer outbufs[1];
|
||||
SECURITY_STATUS status;
|
||||
TimeStamp ts_expiry;
|
||||
|
||||
sspi_flags = ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY |
|
||||
ISC_RET_EXTENDED_ERROR |
|
||||
ISC_REQ_ALLOCATE_MEMORY |
|
||||
ISC_REQ_MANUAL_CRED_VALIDATION;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
|
||||
|
||||
outbufs[0].pvBuffer = NULL;
|
||||
outbufs[0].BufferType = SECBUFFER_TOKEN;
|
||||
outbufs[0].cbBuffer = 0;
|
||||
|
||||
outbuf.cBuffers = 1;
|
||||
outbuf.pBuffers = outbufs;
|
||||
outbuf.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
#ifdef UNICODE
|
||||
status = global->sspi->InitializeSecurityContextW(
|
||||
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
|
||||
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
|
||||
&outbuf, &sspi_flags_out, &ts_expiry);
|
||||
#else /* UNICODE */
|
||||
status = global->sspi->InitializeSecurityContextA(
|
||||
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
|
||||
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
|
||||
&outbuf, &sspi_flags_out, &ts_expiry);
|
||||
#endif /* UNICODE */
|
||||
if (status != SEC_I_CONTINUE_NEEDED) {
|
||||
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
|
||||
"failed - 0x%x",
|
||||
__func__, (unsigned int) status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
|
||||
struct wpabuf *buf;
|
||||
wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
|
||||
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
|
||||
conn->start = 0;
|
||||
buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
|
||||
outbufs[0].cbBuffer);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
|
||||
return buf;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
|
||||
#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
|
||||
|
||||
typedef struct _SecPkgContext_EapKeyBlock {
|
||||
BYTE rgbKeys[128];
|
||||
BYTE rgbIVs[64];
|
||||
} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
|
||||
#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
|
||||
|
||||
static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
SecPkgContext_EapKeyBlock kb;
|
||||
|
||||
/* Note: Windows NT and Windows Me/98/95 do not support getting
|
||||
* EapKeyBlock */
|
||||
|
||||
status = global->sspi->QueryContextAttributes(
|
||||
&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
|
||||
if (status != SEC_E_OK) {
|
||||
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
|
||||
"SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
|
||||
__func__, (int) status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
|
||||
kb.rgbKeys, sizeof(kb.rgbKeys));
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
|
||||
kb.rgbIVs, sizeof(kb.rgbIVs));
|
||||
|
||||
os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
|
||||
conn->eap_tls_prf_set = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
DWORD sspi_flags, sspi_flags_out;
|
||||
SecBufferDesc inbuf, outbuf;
|
||||
SecBuffer inbufs[2], outbufs[1];
|
||||
SECURITY_STATUS status;
|
||||
TimeStamp ts_expiry;
|
||||
struct wpabuf *out_buf = NULL;
|
||||
|
||||
if (appl_data)
|
||||
*appl_data = NULL;
|
||||
|
||||
if (conn->start)
|
||||
return tls_conn_hs_clienthello(global, conn);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
|
||||
(int) wpabuf_len(in_data));
|
||||
|
||||
sspi_flags = ISC_REQ_REPLAY_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY |
|
||||
ISC_RET_EXTENDED_ERROR |
|
||||
ISC_REQ_ALLOCATE_MEMORY |
|
||||
ISC_REQ_MANUAL_CRED_VALIDATION;
|
||||
|
||||
/* Input buffer for Schannel */
|
||||
inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
|
||||
inbufs[0].cbBuffer = wpabuf_len(in_data);
|
||||
inbufs[0].BufferType = SECBUFFER_TOKEN;
|
||||
|
||||
/* Place for leftover data from Schannel */
|
||||
inbufs[1].pvBuffer = NULL;
|
||||
inbufs[1].cbBuffer = 0;
|
||||
inbufs[1].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
inbuf.cBuffers = 2;
|
||||
inbuf.pBuffers = inbufs;
|
||||
inbuf.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
/* Output buffer for Schannel */
|
||||
outbufs[0].pvBuffer = NULL;
|
||||
outbufs[0].cbBuffer = 0;
|
||||
outbufs[0].BufferType = SECBUFFER_TOKEN;
|
||||
|
||||
outbuf.cBuffers = 1;
|
||||
outbuf.pBuffers = outbufs;
|
||||
outbuf.ulVersion = SECBUFFER_VERSION;
|
||||
|
||||
#ifdef UNICODE
|
||||
status = global->sspi->InitializeSecurityContextW(
|
||||
&conn->creds, &conn->context, NULL, sspi_flags, 0,
|
||||
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
|
||||
&outbuf, &sspi_flags_out, &ts_expiry);
|
||||
#else /* UNICODE */
|
||||
status = global->sspi->InitializeSecurityContextA(
|
||||
&conn->creds, &conn->context, NULL, sspi_flags, 0,
|
||||
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
|
||||
&outbuf, &sspi_flags_out, &ts_expiry);
|
||||
#endif /* UNICODE */
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
|
||||
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
|
||||
"intype[1]=%d outlen[0]=%d",
|
||||
(int) status, (int) inbufs[0].cbBuffer,
|
||||
(int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
|
||||
(int) inbufs[1].BufferType,
|
||||
(int) outbufs[0].cbBuffer);
|
||||
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
|
||||
(FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
|
||||
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
|
||||
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
|
||||
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
|
||||
out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
|
||||
outbufs[0].cbBuffer);
|
||||
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
|
||||
outbufs[0].pvBuffer = NULL;
|
||||
if (out_buf == NULL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case SEC_E_INCOMPLETE_MESSAGE:
|
||||
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
|
||||
break;
|
||||
case SEC_I_CONTINUE_NEEDED:
|
||||
wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
|
||||
break;
|
||||
case SEC_E_OK:
|
||||
/* TODO: verify server certificate chain */
|
||||
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
|
||||
"completed successfully");
|
||||
conn->established = 1;
|
||||
tls_get_eap(global, conn);
|
||||
|
||||
/* Need to return something to get final TLS ACK. */
|
||||
if (out_buf == NULL)
|
||||
out_buf = wpabuf_alloc(0);
|
||||
|
||||
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
|
||||
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
|
||||
"application data",
|
||||
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
|
||||
if (appl_data) {
|
||||
*appl_data = wpabuf_alloc_copy(
|
||||
outbufs[1].pvBuffer,
|
||||
outbufs[1].cbBuffer);
|
||||
}
|
||||
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
|
||||
inbufs[1].pvBuffer = NULL;
|
||||
}
|
||||
break;
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
|
||||
break;
|
||||
case SEC_E_WRONG_PRINCIPAL:
|
||||
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
|
||||
break;
|
||||
case SEC_E_INTERNAL_ERROR:
|
||||
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FAILED(status)) {
|
||||
wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
|
||||
"(out_buf=%p)", out_buf);
|
||||
conn->failed++;
|
||||
global->sspi->DeleteSecurityContext(&conn->context);
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
|
||||
/* TODO: Can this happen? What to do with this data? */
|
||||
wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
|
||||
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
|
||||
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
|
||||
inbufs[1].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
return out_buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
SECURITY_STATUS status;
|
||||
SecBufferDesc buf;
|
||||
SecBuffer bufs[4];
|
||||
SecPkgContext_StreamSizes sizes;
|
||||
int i;
|
||||
struct wpabuf *out;
|
||||
|
||||
status = global->sspi->QueryContextAttributes(&conn->context,
|
||||
SECPKG_ATTR_STREAM_SIZES,
|
||||
&sizes);
|
||||
if (status != SEC_E_OK) {
|
||||
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
|
||||
__func__,
|
||||
(unsigned int) sizes.cbHeader,
|
||||
(unsigned int) sizes.cbTrailer);
|
||||
|
||||
out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
|
||||
sizes.cbTrailer);
|
||||
|
||||
os_memset(&bufs, 0, sizeof(bufs));
|
||||
bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
|
||||
bufs[0].cbBuffer = sizes.cbHeader;
|
||||
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
|
||||
|
||||
bufs[1].pvBuffer = wpabuf_put(out, 0);
|
||||
wpabuf_put_buf(out, in_data);
|
||||
bufs[1].cbBuffer = wpabuf_len(in_data);
|
||||
bufs[1].BufferType = SECBUFFER_DATA;
|
||||
|
||||
bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
|
||||
bufs[2].cbBuffer = sizes.cbTrailer;
|
||||
bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
|
||||
|
||||
buf.ulVersion = SECBUFFER_VERSION;
|
||||
buf.cBuffers = 3;
|
||||
buf.pBuffers = bufs;
|
||||
|
||||
status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
|
||||
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
|
||||
"len[2]=%d type[2]=%d",
|
||||
(int) status,
|
||||
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
|
||||
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
|
||||
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
|
||||
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
|
||||
"out_data=%p bufs %p %p %p",
|
||||
wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
|
||||
bufs[2].pvBuffer);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
|
||||
{
|
||||
wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
|
||||
bufs[i].pvBuffer, bufs[i].cbBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == SEC_E_OK) {
|
||||
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
|
||||
wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
|
||||
"from EncryptMessage", out);
|
||||
return out;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
|
||||
__func__, (int) status);
|
||||
wpabuf_free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
SECURITY_STATUS status;
|
||||
SecBufferDesc buf;
|
||||
SecBuffer bufs[4];
|
||||
int i;
|
||||
struct wpabuf *out, *tmp;
|
||||
|
||||
wpa_hexdump_buf(MSG_MSGDUMP,
|
||||
"Schannel: Encrypted data to DecryptMessage", in_data);
|
||||
os_memset(&bufs, 0, sizeof(bufs));
|
||||
tmp = wpabuf_dup(in_data);
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
bufs[0].pvBuffer = wpabuf_mhead(tmp);
|
||||
bufs[0].cbBuffer = wpabuf_len(in_data);
|
||||
bufs[0].BufferType = SECBUFFER_DATA;
|
||||
|
||||
bufs[1].BufferType = SECBUFFER_EMPTY;
|
||||
bufs[2].BufferType = SECBUFFER_EMPTY;
|
||||
bufs[3].BufferType = SECBUFFER_EMPTY;
|
||||
|
||||
buf.ulVersion = SECBUFFER_VERSION;
|
||||
buf.cBuffers = 4;
|
||||
buf.pBuffers = bufs;
|
||||
|
||||
status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
|
||||
NULL);
|
||||
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
|
||||
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
|
||||
"len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
|
||||
(int) status,
|
||||
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
|
||||
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
|
||||
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
|
||||
(int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
|
||||
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
|
||||
"out_data=%p bufs %p %p %p %p",
|
||||
wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
|
||||
bufs[2].pvBuffer, bufs[3].pvBuffer);
|
||||
|
||||
switch (status) {
|
||||
case SEC_E_INCOMPLETE_MESSAGE:
|
||||
wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
|
||||
__func__);
|
||||
break;
|
||||
case SEC_E_OK:
|
||||
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (bufs[i].BufferType == SECBUFFER_DATA)
|
||||
break;
|
||||
}
|
||||
if (i == 4) {
|
||||
wpa_printf(MSG_DEBUG, "%s: No output data from "
|
||||
"DecryptMessage", __func__);
|
||||
wpabuf_free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
|
||||
"DecryptMessage",
|
||||
bufs[i].pvBuffer, bufs[i].cbBuffer);
|
||||
out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
|
||||
wpabuf_free(tmp);
|
||||
return out;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
|
||||
__func__, (int) status);
|
||||
wpabuf_free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *ciphers)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_enable_workaround(void *ssl_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
|
||||
int ext_type, const u8 *data,
|
||||
size_t data_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
return conn->failed;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
return conn->read_alerts;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
return conn->write_alerts;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
ALG_ID algs[1];
|
||||
SECURITY_STATUS status;
|
||||
TimeStamp ts_expiry;
|
||||
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
|
||||
if (global->my_cert_store == NULL &&
|
||||
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
|
||||
NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
|
||||
__func__, (unsigned int) GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
|
||||
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
|
||||
algs[0] = CALG_RSA_KEYX;
|
||||
conn->schannel_cred.cSupportedAlgs = 1;
|
||||
conn->schannel_cred.palgSupportedAlgs = algs;
|
||||
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
|
||||
#ifdef UNICODE
|
||||
status = global->sspi->AcquireCredentialsHandleW(
|
||||
NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
|
||||
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
|
||||
#else /* UNICODE */
|
||||
status = global->sspi->AcquireCredentialsHandleA(
|
||||
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
|
||||
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
|
||||
#endif /* UNICODE */
|
||||
if (status != SEC_E_OK) {
|
||||
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
|
||||
"0x%x", __func__, (unsigned int) status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int tls_capabilities(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
|
||||
int tls_ia)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_ia_send_phase_finished(
|
||||
void *tls_ctx, struct tls_connection *conn, int final);
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_ia_final_phase_finished(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
#ifndef APPLE80211_H
|
||||
#define APPLE80211_H
|
||||
|
||||
/*
|
||||
* Apple80211 framework definitions
|
||||
* This is an undocumented interface and the definitions here are based on
|
||||
* information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
|
||||
* whatever related information can be found with google and experiments ;-).
|
||||
*/
|
||||
|
||||
typedef struct __WirelessRef *WirelessRef;
|
||||
typedef SInt32 WirelessError;
|
||||
#define errWirelessNoError 0
|
||||
|
||||
typedef struct WirelessInfo {
|
||||
UInt16 link_qual;
|
||||
UInt16 comms_qual;
|
||||
UInt16 signal;
|
||||
UInt16 noise;
|
||||
UInt16 port_stat;
|
||||
UInt16 client_mode;
|
||||
UInt16 res1;
|
||||
UInt16 power;
|
||||
UInt16 res2;
|
||||
UInt8 bssID[6];
|
||||
UInt8 ssid[34];
|
||||
} WirelessInfo;
|
||||
|
||||
typedef struct WirelessInfo2 {
|
||||
/* TODO - these are probably not in correct order or complete */
|
||||
WirelessInfo info1;
|
||||
UInt8 macAddress[6];
|
||||
} WirelessInfo2;
|
||||
|
||||
typedef struct WirelessNetworkInfo {
|
||||
UInt16 channel;
|
||||
UInt16 noise;
|
||||
UInt16 signal;
|
||||
UInt8 bssid[6];
|
||||
UInt16 beacon_int;
|
||||
UInt16 capability;
|
||||
UInt16 ssid_len;
|
||||
UInt8 ssid[32];
|
||||
} WirelessNetworkInfo;
|
||||
|
||||
typedef int wirelessKeyType; /* TODO */
|
||||
|
||||
int WirelessIsAvailable(void);
|
||||
WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
|
||||
WirelessError WirelessDetach(WirelessRef ref);
|
||||
WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
|
||||
void *out_ptr, int out_bytes);
|
||||
WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
|
||||
WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
|
||||
WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
|
||||
WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
|
||||
WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
|
||||
WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
|
||||
WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
|
||||
UInt32 strip_dups);
|
||||
WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
|
||||
CFArrayRef *ibss_results, UInt32 strip_dups);
|
||||
WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
|
||||
UInt32 strip_dups, CFStringRef ssid);
|
||||
WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
|
||||
UInt32 strip_dups, CFArrayRef *results);
|
||||
WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
|
||||
WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
|
||||
CFStringRef passwd);
|
||||
WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
|
||||
/*
|
||||
* Set WEP key
|
||||
* ref: wireless reference from WirelessAttach()
|
||||
* type: ?
|
||||
* key_idx: 0..3
|
||||
* key_len: 13 for WEP-104 or 0 for clearing the key
|
||||
* key: Pointer to the key or %NULL if key_len = 0
|
||||
*/
|
||||
WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
|
||||
int key_idx, int key_len,
|
||||
const unsigned char *key);
|
||||
/*
|
||||
* Set WPA key (e.g., PMK for 4-way handshake)
|
||||
* ref: wireless reference from WirelessAttach()
|
||||
* type: 0..4; 1 = PMK
|
||||
* key_len: 16, 32, or 0
|
||||
* key: Pointer to the key or %NULL if key_len = 0
|
||||
*/
|
||||
WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
|
||||
int key_len, const unsigned char *key);
|
||||
WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
|
||||
CFStringRef key);
|
||||
WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
|
||||
CFStringRef key);
|
||||
WirelessError WirelessDisassociate(WirelessRef ref);
|
||||
|
||||
/*
|
||||
* Get a copy of scan results for the given SSID
|
||||
* The returned dictionary includes following entries:
|
||||
* beaconInterval: CFNumber(kCFNumberSInt32Type)
|
||||
* SSID: CFData buffer of the SSID
|
||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
|
||||
* name: Name of the network (SSID string)
|
||||
* BSSID: CFData buffer of the BSSID
|
||||
* channel: CFNumber(kCFNumberSInt32Type)
|
||||
* signal: CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE: CFData
|
||||
* WPSNOPINRequired: CFBoolean
|
||||
* noise: CFNumber(kCFNumberSInt32Type)
|
||||
* capability: CFNumber(kCFNumberSInt32Type)
|
||||
* uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE_Version: CFNumber(kCFNumberSInt32Type)
|
||||
* appleIE_Robust: CFBoolean
|
||||
* WPSConfigured: CFBoolean
|
||||
* scanWasDirected: CFBoolean
|
||||
* appleIE_Product: CFNumber(kCFNumberSInt32Type)
|
||||
* authModes: CFArray of CFNumber(kCFNumberSInt32Type)
|
||||
* multiCipher: CFNumber(kCFNumberSInt32Type)
|
||||
*/
|
||||
CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
|
||||
|
||||
/*
|
||||
* Get information about the current association
|
||||
* The returned dictionary includes following entries:
|
||||
* keyData: CFData buffer of the key (e.g., 32-octet PSK)
|
||||
* multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
|
||||
* channel: CFNumber(kCFNumberSInt32Type)
|
||||
* isIBSS: CFBoolean
|
||||
* authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
|
||||
* 129 = WPA2-Enterprise
|
||||
* isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
|
||||
* SSID: CFData buffer of the SSID
|
||||
* cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
|
||||
*/
|
||||
CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
|
||||
|
||||
WirelessError WirelessConfigure(WirelessRef ref);
|
||||
|
||||
/*
|
||||
* Get ASP information
|
||||
* The returned dictionary includes following entries:
|
||||
* Version: version number (e.g., 3.0)
|
||||
* Channel: channel (e.g., 1)
|
||||
* Vendor: vendor (e.g., 2)
|
||||
*/
|
||||
CFDictionaryRef WirelessGetInfoASP(void);
|
||||
|
||||
/*
|
||||
* Get a copy of the interface dictionary
|
||||
* The returned dictionary has a key,value pairs for wireless interfaces.
|
||||
* The key is the interface name and the value is the driver identifier, e.g.,
|
||||
* en1: com.apple.driver.AirPort.Atheros
|
||||
*/
|
||||
CFDictionaryRef WirelessCopyInterfaceDict(void);
|
||||
|
||||
#endif /* APPLE80211_H */
|
|
@ -1,189 +0,0 @@
|
|||
#include "includes.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "MobileApple80211.h"
|
||||
|
||||
/*
|
||||
* Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
|
||||
* having to link with full Preferences.framework.
|
||||
*/
|
||||
|
||||
static void *aeropuerto = NULL;
|
||||
|
||||
|
||||
int _Apple80211Initialized(void)
|
||||
{
|
||||
return aeropuerto ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
|
||||
|
||||
int Apple80211Open(Apple80211Ref *ctx)
|
||||
{
|
||||
return __Apple80211Open(ctx);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
|
||||
|
||||
int Apple80211Close(Apple80211Ref ctx)
|
||||
{
|
||||
return __Apple80211Close(ctx);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
|
||||
= NULL;
|
||||
|
||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
|
||||
{
|
||||
return __Apple80211GetIfListCopy(handle, list);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
|
||||
CFStringRef interface) = NULL;
|
||||
|
||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
||||
CFStringRef interface)
|
||||
{
|
||||
return __Apple80211BindToInterface(handle, interface);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
|
||||
CFStringRef *name) = NULL;
|
||||
|
||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
||||
CFStringRef *name)
|
||||
{
|
||||
return __Apple80211GetInterfaceNameCopy(handle, name);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
|
||||
CFDictionaryRef *info) = NULL;
|
||||
|
||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
||||
CFDictionaryRef *info)
|
||||
{
|
||||
return __Apple80211GetInfoCopy(handle, info);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
|
||||
|
||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr)
|
||||
{
|
||||
return __Apple80211GetPower(handle, pwr);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
|
||||
|
||||
int Apple80211SetPower(Apple80211Ref handle, char pwr)
|
||||
{
|
||||
return __Apple80211SetPower(handle, pwr);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters) = NULL;
|
||||
|
||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters)
|
||||
{
|
||||
return __Apple80211Scan(handle, list, parameters);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password) = NULL;
|
||||
|
||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password)
|
||||
{
|
||||
return __Apple80211Associate(handle, bss, password);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
|
||||
CFDictionaryRef bss,
|
||||
CFStringRef password,
|
||||
CFDictionaryRef *info) =
|
||||
NULL;
|
||||
|
||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password, CFDictionaryRef *info)
|
||||
{
|
||||
return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
|
||||
}
|
||||
|
||||
|
||||
static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
|
||||
CFDictionaryRef arg2, void *value) = NULL;
|
||||
|
||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
||||
void *value)
|
||||
{
|
||||
return __Apple80211CopyValue(handle, field, arg2, value);
|
||||
}
|
||||
|
||||
|
||||
#define DLSYM(s) \
|
||||
do { \
|
||||
__ ## s = dlsym(aeropuerto, #s); \
|
||||
if (__ ## s == NULL) { \
|
||||
wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
|
||||
"symbol '" #s "' (%s)", dlerror()); \
|
||||
err = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
__attribute__ ((constructor))
|
||||
void _Apple80211_constructor(void)
|
||||
{
|
||||
const char *fname = "/System/Library/SystemConfiguration/"
|
||||
"Aeropuerto.bundle/Aeropuerto";
|
||||
int err = 0;
|
||||
|
||||
aeropuerto = dlopen(fname, RTLD_LAZY);
|
||||
if (!aeropuerto) {
|
||||
wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
|
||||
"for symbols", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
DLSYM(Apple80211Open);
|
||||
DLSYM(Apple80211Close);
|
||||
DLSYM(Apple80211GetIfListCopy);
|
||||
DLSYM(Apple80211BindToInterface);
|
||||
DLSYM(Apple80211GetInterfaceNameCopy);
|
||||
DLSYM(Apple80211GetInfoCopy);
|
||||
DLSYM(Apple80211GetPower);
|
||||
DLSYM(Apple80211SetPower);
|
||||
DLSYM(Apple80211Scan);
|
||||
DLSYM(Apple80211Associate);
|
||||
DLSYM(Apple80211AssociateAndCopyInfo);
|
||||
DLSYM(Apple80211CopyValue);
|
||||
|
||||
if (err) {
|
||||
dlclose(aeropuerto);
|
||||
aeropuerto = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__attribute__ ((destructor))
|
||||
void _Apple80211_destructor(void)
|
||||
{
|
||||
if (aeropuerto) {
|
||||
dlclose(aeropuerto);
|
||||
aeropuerto = NULL;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
#ifndef MOBILEAPPLE80211_H
|
||||
#define MOBILEAPPLE80211_H
|
||||
|
||||
/*
|
||||
* MobileApple80211 interface for iPhone/iPod touch
|
||||
* These functions are available from Aeropuerto.
|
||||
*/
|
||||
|
||||
struct Apple80211;
|
||||
typedef struct Apple80211 *Apple80211Ref;
|
||||
|
||||
int Apple80211Open(Apple80211Ref *ctx);
|
||||
int Apple80211Close(Apple80211Ref ctx);
|
||||
int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
|
||||
int Apple80211BindToInterface(Apple80211Ref handle,
|
||||
CFStringRef interface);
|
||||
int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
|
||||
CFStringRef *name);
|
||||
int Apple80211GetInfoCopy(Apple80211Ref handle,
|
||||
CFDictionaryRef *info);
|
||||
int Apple80211GetPower(Apple80211Ref handle, char *pwr);
|
||||
int Apple80211SetPower(Apple80211Ref handle, char pwr);
|
||||
|
||||
/* parameters can be NULL; returns scan results in CFArrayRef *list;
|
||||
* caller will need to free with CFRelease() */
|
||||
int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
|
||||
CFDictionaryRef parameters);
|
||||
|
||||
int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password);
|
||||
int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
|
||||
CFStringRef password,
|
||||
CFDictionaryRef *info);
|
||||
|
||||
enum {
|
||||
APPLE80211_VALUE_SSID = 1,
|
||||
APPLE80211_VALUE_BSSID = 9
|
||||
};
|
||||
|
||||
int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
|
||||
void *value);
|
||||
|
||||
#endif /* MOBILEAPPLE80211_H */
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,599 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant - driver interaction with old Broadcom wl.o driver
|
||||
* Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
|
||||
* 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.
|
||||
*
|
||||
* Please note that the newer Broadcom driver ("hybrid Linux driver") supports
|
||||
* Linux wireless extensions and does not need (or even work) with this old
|
||||
* driver wrapper. Use driver_wext.c with that driver.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if 0
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h> /* the L2 protocols */
|
||||
#else
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_ether.h> /* The L2 protocols */
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <typedefs.h>
|
||||
|
||||
/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
|
||||
* WRT54G GPL tarball. */
|
||||
#include <wlioctl.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
|
||||
struct wpa_driver_broadcom_data {
|
||||
void *ctx;
|
||||
int ioctl_sock;
|
||||
int event_sock;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
};
|
||||
|
||||
|
||||
#ifndef WLC_DEAUTHENTICATE
|
||||
#define WLC_DEAUTHENTICATE 143
|
||||
#endif
|
||||
#ifndef WLC_DEAUTHENTICATE_WITH_REASON
|
||||
#define WLC_DEAUTHENTICATE_WITH_REASON 201
|
||||
#endif
|
||||
#ifndef WLC_SET_TKIP_COUNTERMEASURES
|
||||
#define WLC_SET_TKIP_COUNTERMEASURES 202
|
||||
#endif
|
||||
|
||||
#if !defined(PSK_ENABLED) /* NEW driver interface */
|
||||
#define WL_VERSION 360130
|
||||
/* wireless authentication bit vector */
|
||||
#define WPA_ENABLED 1
|
||||
#define PSK_ENABLED 2
|
||||
|
||||
#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
|
||||
#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
|
||||
#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
|
||||
|
||||
#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
|
||||
|
||||
typedef wl_wsec_key_t wsec_key_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32 val;
|
||||
struct ether_addr ea;
|
||||
uint16 res;
|
||||
} wlc_deauth_t;
|
||||
|
||||
|
||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
|
||||
static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
|
||||
void *buf, int len)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
wl_ioctl_t ioc;
|
||||
int ret = 0;
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
|
||||
drv->ifname, cmd, len, buf);
|
||||
/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
|
||||
|
||||
ioc.cmd = cmd;
|
||||
ioc.buf = buf;
|
||||
ioc.len = len;
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
ifr.ifr_data = (caddr_t) &ioc;
|
||||
if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
|
||||
if (cmd != WLC_GET_MAGIC)
|
||||
perror(ifr.ifr_name);
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
|
||||
cmd, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
|
||||
return 0;
|
||||
|
||||
os_memset(bssid, 0, ETH_ALEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t s;
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
|
||||
return -1;
|
||||
|
||||
os_memcpy(ssid, s.SSID, s.SSID_len);
|
||||
return s.SSID_len;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
unsigned int wauth, wsec;
|
||||
struct ether_addr ea;
|
||||
|
||||
os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
|
||||
if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
||||
-1 ||
|
||||
broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
|
||||
return -1;
|
||||
|
||||
if (enable) {
|
||||
wauth = PSK_ENABLED;
|
||||
wsec = TKIP_ENABLED;
|
||||
} else {
|
||||
wauth = 255;
|
||||
wsec &= ~(TKIP_ENABLED | AES_ENABLED);
|
||||
}
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
|
||||
-1 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
|
||||
return -1;
|
||||
|
||||
/* FIX: magic number / error handling? */
|
||||
broadcom_ioctl(drv, 122, &ea, sizeof(ea));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
|
||||
enum wpa_alg alg,
|
||||
const u8 *addr, int key_idx, int set_tx,
|
||||
const u8 *seq, size_t seq_len,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
int ret;
|
||||
wsec_key_t wkt;
|
||||
|
||||
os_memset(&wkt, 0, sizeof wkt);
|
||||
wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
|
||||
set_tx ? "PRIMARY " : "", key_idx, alg);
|
||||
if (key && key_len > 0)
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
|
||||
|
||||
switch (alg) {
|
||||
case WPA_ALG_NONE:
|
||||
wkt.algo = CRYPTO_ALGO_OFF;
|
||||
break;
|
||||
case WPA_ALG_WEP:
|
||||
wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
|
||||
break;
|
||||
case WPA_ALG_TKIP:
|
||||
wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
|
||||
break;
|
||||
case WPA_ALG_CCMP:
|
||||
wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
|
||||
* AES_OCB_MSDU, AES_OCB_MPDU? */
|
||||
break;
|
||||
default:
|
||||
wkt.algo = CRYPTO_ALGO_NALG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (seq && seq_len > 0)
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
|
||||
|
||||
if (addr)
|
||||
wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
|
||||
|
||||
wkt.index = key_idx;
|
||||
wkt.len = key_len;
|
||||
if (key && key_len > 0) {
|
||||
os_memcpy(wkt.data, key, key_len);
|
||||
if (key_len == 32) {
|
||||
/* hack hack hack XXX */
|
||||
os_memcpy(&wkt.data[16], &key[24], 8);
|
||||
os_memcpy(&wkt.data[24], &key[16], 8);
|
||||
}
|
||||
}
|
||||
/* wkt.algo = CRYPTO_ALGO_...; */
|
||||
wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
|
||||
if (addr && set_tx)
|
||||
os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
|
||||
ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
|
||||
if (addr && set_tx) {
|
||||
/* FIX: magic number / error handling? */
|
||||
broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
char buf[8192];
|
||||
int left;
|
||||
wl_wpa_header_t *wwh;
|
||||
union wpa_event_data data;
|
||||
u8 *resp_ies = NULL;
|
||||
|
||||
if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
|
||||
return;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
|
||||
|
||||
if ((size_t) left < sizeof(wl_wpa_header_t))
|
||||
return;
|
||||
|
||||
wwh = (wl_wpa_header_t *) buf;
|
||||
|
||||
if (wwh->snap.type != WL_WPA_ETHER_TYPE)
|
||||
return;
|
||||
if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
|
||||
return;
|
||||
|
||||
os_memset(&data, 0, sizeof(data));
|
||||
|
||||
switch (wwh->type) {
|
||||
case WLC_ASSOC_MSG:
|
||||
left -= WL_WPA_HEADER_LEN;
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
|
||||
left);
|
||||
if (left > 0) {
|
||||
resp_ies = os_malloc(left);
|
||||
if (resp_ies == NULL)
|
||||
return;
|
||||
os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
|
||||
data.assoc_info.resp_ies = resp_ies;
|
||||
data.assoc_info.resp_ies_len = left;
|
||||
}
|
||||
|
||||
wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
|
||||
os_free(resp_ies);
|
||||
break;
|
||||
case WLC_DISASSOC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
|
||||
wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
|
||||
break;
|
||||
case WLC_PTK_MIC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
|
||||
data.michael_mic_failure.unicast = 1;
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
break;
|
||||
case WLC_GTK_MIC_MSG:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
|
||||
data.michael_mic_failure.unicast = 0;
|
||||
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
|
||||
wwh->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_ll ll;
|
||||
struct wpa_driver_broadcom_data *drv;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* open socket to kernel */
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
return NULL;
|
||||
}
|
||||
/* do it */
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror(ifr.ifr_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->ioctl_sock = s;
|
||||
|
||||
s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
|
||||
if (s < 0) {
|
||||
perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&ll, 0, sizeof(ll));
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_protocol = ntohs(ETH_P_802_2);
|
||||
ll.sll_ifindex = ifr.ifr_ifindex;
|
||||
ll.sll_hatype = 0;
|
||||
ll.sll_pkttype = PACKET_HOST;
|
||||
ll.sll_halen = 0;
|
||||
|
||||
if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
|
||||
perror("bind(netlink)");
|
||||
close(s);
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
|
||||
NULL);
|
||||
drv->event_sock = s;
|
||||
wpa_driver_broadcom_set_wpa(drv, 1);
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
static void wpa_driver_broadcom_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wpa_driver_broadcom_set_wpa(drv, 0);
|
||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
||||
eloop_unregister_read_sock(drv->event_sock);
|
||||
close(drv->event_sock);
|
||||
close(drv->ioctl_sock);
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_countermeasures(void *priv,
|
||||
int enabled)
|
||||
{
|
||||
#if 0
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
/* FIX: ? */
|
||||
return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
|
||||
sizeof(enabled));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
|
||||
int _restrict = (enabled ? 1 : 0);
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
|
||||
&_restrict, sizeof(_restrict)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
|
||||
&_restrict, sizeof(_restrict)) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_scan(void *priv,
|
||||
struct wpa_driver_scan_params *params)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t wst = { 0, "" };
|
||||
const u8 *ssid = params->ssids[0].ssid;
|
||||
size_t ssid_len = params->ssids[0].ssid_len;
|
||||
|
||||
if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
|
||||
wst.SSID_len = ssid_len;
|
||||
os_memcpy(wst.SSID, ssid, ssid_len);
|
||||
}
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
|
||||
return -1;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const int frequency_list[] = {
|
||||
2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
||||
2447, 2452, 2457, 2462, 2467, 2472, 2484
|
||||
};
|
||||
|
||||
struct bss_ie_hdr {
|
||||
u8 elem_id;
|
||||
u8 len;
|
||||
u8 oui[3];
|
||||
/* u8 oui_type; */
|
||||
/* u16 version; */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct wpa_scan_results *
|
||||
wpa_driver_broadcom_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
char *buf;
|
||||
wl_scan_results_t *wsr;
|
||||
wl_bss_info_t *wbi;
|
||||
size_t ap_num;
|
||||
struct wpa_scan_results *res;
|
||||
|
||||
buf = os_malloc(WLC_IOCTL_MAXLEN);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
wsr = (wl_scan_results_t *) buf;
|
||||
|
||||
wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
|
||||
wsr->version = 107;
|
||||
wsr->count = 0;
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = os_zalloc(sizeof(*res));
|
||||
if (res == NULL) {
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
|
||||
if (res->res == NULL) {
|
||||
os_free(res);
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
|
||||
struct wpa_scan_res *r;
|
||||
r = os_malloc(sizeof(*r) + wbi->ie_length);
|
||||
if (r == NULL)
|
||||
break;
|
||||
res->res[res->num++] = r;
|
||||
|
||||
os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
|
||||
r->freq = frequency_list[wbi->channel - 1];
|
||||
/* get ie's */
|
||||
os_memcpy(r + 1, wbi + 1, wbi->ie_length);
|
||||
r->ie_len = wbi->ie_length;
|
||||
|
||||
wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
|
||||
"BSSes)",
|
||||
wsr->buflen, (unsigned long) ap_num);
|
||||
|
||||
os_free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_deauth_t wdt;
|
||||
wdt.val = reason_code;
|
||||
os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
|
||||
wdt.res = 0x7fff;
|
||||
return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
|
||||
sizeof(wdt));
|
||||
}
|
||||
|
||||
static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
|
||||
int reason_code)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
wpa_driver_broadcom_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_broadcom_data *drv = priv;
|
||||
wlc_ssid_t s;
|
||||
int infra = 1;
|
||||
int auth = 0;
|
||||
int wsec = 4;
|
||||
int dummy;
|
||||
int wpa_auth;
|
||||
int ret;
|
||||
|
||||
ret = wpa_driver_broadcom_set_drop_unencrypted(
|
||||
drv, params->drop_unencrypted);
|
||||
|
||||
s.SSID_len = params->ssid_len;
|
||||
os_memcpy(s.SSID, params->ssid, params->ssid_len);
|
||||
|
||||
switch (params->pairwise_suite) {
|
||||
case CIPHER_WEP40:
|
||||
case CIPHER_WEP104:
|
||||
wsec = 1;
|
||||
break;
|
||||
|
||||
case CIPHER_TKIP:
|
||||
wsec = 2;
|
||||
break;
|
||||
|
||||
case CIPHER_CCMP:
|
||||
wsec = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
wsec = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (params->key_mgmt_suite) {
|
||||
case KEY_MGMT_802_1X:
|
||||
wpa_auth = 1;
|
||||
break;
|
||||
|
||||
case KEY_MGMT_PSK:
|
||||
wpa_auth = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_auth = 255;
|
||||
break;
|
||||
}
|
||||
|
||||
/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
|
||||
* group_suite, key_mgmt_suite);
|
||||
* broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
|
||||
* wl join uses wlc_sec_wep here, not wlc_set_wsec */
|
||||
|
||||
if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
|
||||
sizeof(wpa_auth)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
|
||||
broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_broadcom_ops = {
|
||||
.name = "broadcom",
|
||||
.desc = "Broadcom wl.o driver",
|
||||
.get_bssid = wpa_driver_broadcom_get_bssid,
|
||||
.get_ssid = wpa_driver_broadcom_get_ssid,
|
||||
.set_key = wpa_driver_broadcom_set_key,
|
||||
.init = wpa_driver_broadcom_init,
|
||||
.deinit = wpa_driver_broadcom_deinit,
|
||||
.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
|
||||
.scan2 = wpa_driver_broadcom_scan,
|
||||
.get_scan_results2 = wpa_driver_broadcom_get_scan_results,
|
||||
.deauthenticate = wpa_driver_broadcom_deauthenticate,
|
||||
.disassociate = wpa_driver_broadcom_disassociate,
|
||||
.associate = wpa_driver_broadcom_associate,
|
||||
};
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
|
||||
* 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"
|
||||
#define Boolean __DummyBoolean
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#undef Boolean
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
#include "MobileApple80211.h"
|
||||
|
||||
struct wpa_driver_iphone_data {
|
||||
void *ctx;
|
||||
Apple80211Ref wireless_ctx;
|
||||
CFArrayRef scan_results;
|
||||
int ctrl_power;
|
||||
};
|
||||
|
||||
|
||||
static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
|
||||
{
|
||||
const void *res;
|
||||
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
|
||||
kCFStringEncodingMacRoman);
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
res = CFDictionaryGetValue(dict, str);
|
||||
CFRelease(str);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
CFDataRef data;
|
||||
int err, len;
|
||||
|
||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
|
||||
&data);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
|
||||
"failed: %d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = CFDataGetLength(data);
|
||||
if (len > 32) {
|
||||
CFRelease(data);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(ssid, CFDataGetBytePtr(data), len);
|
||||
CFRelease(data);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
CFStringRef data;
|
||||
int err;
|
||||
int a1, a2, a3, a4, a5, a6;
|
||||
|
||||
err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
|
||||
&data);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
|
||||
"failed: %d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
|
||||
"%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
|
||||
bssid[0] = a1;
|
||||
bssid[1] = a2;
|
||||
bssid[2] = a3;
|
||||
bssid[3] = a4;
|
||||
bssid[4] = a5;
|
||||
bssid[5] = a6;
|
||||
|
||||
CFRelease(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int err;
|
||||
|
||||
if (drv->scan_results) {
|
||||
CFRelease(drv->scan_results);
|
||||
drv->scan_results = NULL;
|
||||
}
|
||||
|
||||
err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
|
||||
err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_scan_results(void *priv,
|
||||
struct wpa_scan_result *results,
|
||||
size_t max_size)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
size_t i, num;
|
||||
|
||||
if (drv->scan_results == NULL)
|
||||
return 0;
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
if (num > max_size)
|
||||
num = max_size;
|
||||
os_memset(results, 0, num * sizeof(struct wpa_scan_result));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct wpa_scan_result *res = &results[i];
|
||||
CFDictionaryRef dict =
|
||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
||||
CFDataRef data;
|
||||
CFStringRef str;
|
||||
CFNumberRef num;
|
||||
int val;
|
||||
|
||||
data = cfdict_get_key_str(dict, "SSID");
|
||||
if (data) {
|
||||
res->ssid_len = CFDataGetLength(data);
|
||||
if (res->ssid_len > 32)
|
||||
res->ssid_len = 32;
|
||||
os_memcpy(res->ssid, CFDataGetBytePtr(data),
|
||||
res->ssid_len);
|
||||
}
|
||||
|
||||
str = cfdict_get_key_str(dict, "BSSID");
|
||||
if (str) {
|
||||
int a1, a2, a3, a4, a5, a6;
|
||||
sscanf(CFStringGetCStringPtr(
|
||||
str, kCFStringEncodingMacRoman),
|
||||
"%x:%x:%x:%x:%x:%x",
|
||||
&a1, &a2, &a3, &a4, &a5, &a6);
|
||||
res->bssid[0] = a1;
|
||||
res->bssid[1] = a2;
|
||||
res->bssid[2] = a3;
|
||||
res->bssid[3] = a4;
|
||||
res->bssid[4] = a5;
|
||||
res->bssid[5] = a6;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "CAPABILITIES");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->caps = val;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "CHANNEL");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->freq = 2407 + val * 5;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "RSSI");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->level = val;
|
||||
}
|
||||
|
||||
num = cfdict_get_key_str(dict, "NOISE");
|
||||
if (num) {
|
||||
if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
|
||||
res->noise = val;
|
||||
}
|
||||
|
||||
data = cfdict_get_key_str(dict, "IE");
|
||||
if (data) {
|
||||
u8 *ptr = (u8 *) CFDataGetBytePtr(data);
|
||||
int len = CFDataGetLength(data);
|
||||
u8 *pos = ptr, *end = ptr + len;
|
||||
|
||||
while (pos + 2 < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
break;
|
||||
if (pos[0] == WLAN_EID_RSN &&
|
||||
pos[1] <= SSID_MAX_WPA_IE_LEN) {
|
||||
os_memcpy(res->rsn_ie, pos,
|
||||
2 + pos[1]);
|
||||
res->rsn_ie_len = 2 + pos[1];
|
||||
}
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
|
||||
pos[1] > 4 && pos[2] == 0x00 &&
|
||||
pos[3] == 0x50 && pos[4] == 0xf2 &&
|
||||
pos[5] == 0x01) {
|
||||
os_memcpy(res->wpa_ie, pos,
|
||||
2 + pos[1]);
|
||||
res->wpa_ie_len = 2 + pos[1];
|
||||
}
|
||||
|
||||
pos = pos + 2 + pos[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = eloop_ctx;
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
|
||||
eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
|
||||
drv, drv->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_associate(
|
||||
void *priv, struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int i, num, err;
|
||||
size_t ssid_len;
|
||||
CFDictionaryRef bss = NULL;
|
||||
|
||||
/*
|
||||
* TODO: Consider generating parameters instead of just using an entry
|
||||
* from scan results in order to support ap_scan=2.
|
||||
*/
|
||||
|
||||
if (drv->scan_results == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
|
||||
"associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
CFDictionaryRef dict =
|
||||
CFArrayGetValueAtIndex(drv->scan_results, i);
|
||||
CFDataRef data;
|
||||
|
||||
data = cfdict_get_key_str(dict, "SSID");
|
||||
if (data == NULL)
|
||||
continue;
|
||||
|
||||
ssid_len = CFDataGetLength(data);
|
||||
if (ssid_len != params->ssid_len ||
|
||||
os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
|
||||
!= 0)
|
||||
continue;
|
||||
|
||||
bss = dict;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bss == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
|
||||
"results - cannot associate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
|
||||
"from scan results");
|
||||
|
||||
err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
|
||||
"%d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver is actually already associated; report association from an
|
||||
* eloop callback.
|
||||
*/
|
||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
|
||||
drv->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx, const u8 *seq,
|
||||
size_t seq_len, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
/*
|
||||
* TODO: Need to either support configuring PMK for 4-way handshake or
|
||||
* PTK for TKIP/CCMP.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
os_memset(capa, 0, sizeof(*capa));
|
||||
|
||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
||||
WPA_DRIVER_AUTH_LEAP;
|
||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv;
|
||||
int err;
|
||||
char power;
|
||||
CFStringRef name;
|
||||
CFDictionaryRef dict;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
err = Apple80211Open(&drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
|
||||
err);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
|
||||
kCFStringEncodingISOLatin1);
|
||||
if (name == NULL) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = Apple80211BindToInterface(drv->wireless_ctx, name);
|
||||
CFRelease(name);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
|
||||
"failed: %d", err);
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = Apple80211GetPower(drv->wireless_ctx, &power);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
|
||||
err);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
|
||||
|
||||
if (!power) {
|
||||
drv->ctrl_power = 1;
|
||||
err = Apple80211SetPower(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
|
||||
"failed: %d", err);
|
||||
Apple80211Close(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
|
||||
if (err == 0) {
|
||||
CFShow(dict);
|
||||
CFRelease(dict);
|
||||
} else {
|
||||
printf("Apple80211GetInfoCopy: %d\n", err);
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_iphone_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_iphone_data *drv = priv;
|
||||
int err;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
|
||||
eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
|
||||
|
||||
if (drv->ctrl_power) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
|
||||
err = Apple80211SetPower(drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
|
||||
"failed: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
err = Apple80211Close(drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
|
||||
err);
|
||||
}
|
||||
|
||||
if (drv->scan_results)
|
||||
CFRelease(drv->scan_results);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_iphone_ops = {
|
||||
.name = "iphone",
|
||||
.desc = "iPhone/iPod touch Apple80211 driver",
|
||||
.get_ssid = wpa_driver_iphone_get_ssid,
|
||||
.get_bssid = wpa_driver_iphone_get_bssid,
|
||||
.init = wpa_driver_iphone_init,
|
||||
.deinit = wpa_driver_iphone_deinit,
|
||||
.scan = wpa_driver_iphone_scan,
|
||||
.get_scan_results = wpa_driver_iphone_get_scan_results,
|
||||
.associate = wpa_driver_iphone_associate,
|
||||
.set_key = wpa_driver_iphone_set_key,
|
||||
.get_capa = wpa_driver_iphone_get_capa,
|
||||
};
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,459 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant - Mac OS X Apple80211 driver interface
|
||||
* 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"
|
||||
#define Boolean __DummyBoolean
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#undef Boolean
|
||||
|
||||
#include "common.h"
|
||||
#include "driver.h"
|
||||
#include "eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
|
||||
#include "Apple80211.h"
|
||||
|
||||
struct wpa_driver_osx_data {
|
||||
void *ctx;
|
||||
WirelessRef wireless_ctx;
|
||||
CFArrayRef scan_results;
|
||||
};
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
extern int wpa_debug_level;
|
||||
|
||||
static void dump_dict_cb(const void *key, const void *value, void *context)
|
||||
{
|
||||
if (MSG_DEBUG < wpa_debug_level)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Key:");
|
||||
CFShow(key);
|
||||
wpa_printf(MSG_DEBUG, "Value:");
|
||||
CFShow(value);
|
||||
}
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
|
||||
{
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
|
||||
title, (unsigned int) CFDictionaryGetCount(dict));
|
||||
CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
WirelessInfo info;
|
||||
int len;
|
||||
|
||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
||||
(int) err);
|
||||
return -1;
|
||||
}
|
||||
if (!info.power) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (len = 0; len < 32; len++)
|
||||
if (info.ssid[len] == 0)
|
||||
break;
|
||||
|
||||
os_memcpy(ssid, info.ssid, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
WirelessInfo info;
|
||||
|
||||
err = WirelessGetInfo(drv->wireless_ctx, &info);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
|
||||
(int) err);
|
||||
return -1;
|
||||
}
|
||||
if (!info.power) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(bssid, info.bssID, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
const u8 *ssid = params->ssids[0].ssid;
|
||||
size_t ssid_len = params->ssids[0].ssid_len;
|
||||
|
||||
if (drv->scan_results) {
|
||||
CFRelease(drv->scan_results);
|
||||
drv->scan_results = NULL;
|
||||
}
|
||||
|
||||
if (ssid) {
|
||||
CFStringRef data;
|
||||
data = CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||
ssid, ssid_len,
|
||||
kCFStringEncodingISOLatin1,
|
||||
FALSE);
|
||||
if (data == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
|
||||
"failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = WirelessDirectedScan(drv->wireless_ctx,
|
||||
&drv->scan_results, 0, data);
|
||||
CFRelease(data);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
|
||||
"failed: 0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
|
||||
drv->ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
|
||||
WirelessNetworkInfo *info)
|
||||
{
|
||||
struct wpa_scan_res *result, **tmp;
|
||||
size_t extra_len;
|
||||
u8 *pos;
|
||||
|
||||
extra_len = 2 + info->ssid_len;
|
||||
|
||||
result = os_zalloc(sizeof(*result) + extra_len);
|
||||
if (result == NULL)
|
||||
return;
|
||||
os_memcpy(result->bssid, info->bssid, ETH_ALEN);
|
||||
result->freq = 2407 + info->channel * 5;
|
||||
//result->beacon_int =;
|
||||
result->caps = info->capability;
|
||||
//result->qual = info->signal;
|
||||
result->noise = info->noise;
|
||||
|
||||
pos = (u8 *)(result + 1);
|
||||
|
||||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = info->ssid_len;
|
||||
os_memcpy(pos, info->ssid, info->ssid_len);
|
||||
pos += info->ssid_len;
|
||||
|
||||
result->ie_len = pos - (u8 *)(result + 1);
|
||||
|
||||
tmp = os_realloc(res->res,
|
||||
(res->num + 1) * sizeof(struct wpa_scan_res *));
|
||||
if (tmp == NULL) {
|
||||
os_free(result);
|
||||
return;
|
||||
}
|
||||
tmp[res->num++] = result;
|
||||
res->res = tmp;
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
struct wpa_scan_results *res;
|
||||
size_t i, num;
|
||||
|
||||
if (drv->scan_results == NULL)
|
||||
return 0;
|
||||
|
||||
num = CFArrayGetCount(drv->scan_results);
|
||||
|
||||
res = os_zalloc(sizeof(*res));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
|
||||
CFDataGetBytePtr(CFArrayGetValueAtIndex(
|
||||
drv->scan_results, i)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = eloop_ctx;
|
||||
u8 bssid[ETH_ALEN];
|
||||
CFDictionaryRef ai;
|
||||
|
||||
if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
|
||||
eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
|
||||
drv, drv->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
ai = WirelessGetAssociationInfo(drv->wireless_ctx);
|
||||
if (ai) {
|
||||
wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
|
||||
CFRelease(ai);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
|
||||
}
|
||||
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_associate(void *priv,
|
||||
struct wpa_driver_associate_params *params)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
CFDataRef ssid;
|
||||
CFStringRef key;
|
||||
int assoc_type;
|
||||
|
||||
ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
|
||||
params->ssid_len);
|
||||
if (ssid == NULL)
|
||||
return -1;
|
||||
|
||||
/* TODO: support for WEP */
|
||||
if (params->key_mgmt_suite == KEY_MGMT_PSK) {
|
||||
if (params->passphrase == NULL)
|
||||
return -1;
|
||||
key = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
params->passphrase,
|
||||
kCFStringEncodingISOLatin1);
|
||||
if (key == NULL) {
|
||||
CFRelease(ssid);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
key = NULL;
|
||||
|
||||
if (params->key_mgmt_suite == KEY_MGMT_NONE)
|
||||
assoc_type = 0;
|
||||
else
|
||||
assoc_type = 4;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
|
||||
assoc_type, key);
|
||||
err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
|
||||
CFRelease(ssid);
|
||||
if (key)
|
||||
CFRelease(key);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Driver is actually already associated; report association from an
|
||||
* eloop callback.
|
||||
*/
|
||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
||||
eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
|
||||
drv->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_set_key(const char *ifname, void *priv,
|
||||
enum wpa_alg alg, const u8 *addr,
|
||||
int key_idx, int set_tx, const u8 *seq,
|
||||
size_t seq_len, const u8 *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
|
||||
if (alg == WPA_ALG_WEP) {
|
||||
err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
|
||||
key);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (alg == WPA_ALG_PMK) {
|
||||
err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
|
||||
if (err != 0) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
os_memset(capa, 0, sizeof(*capa));
|
||||
|
||||
capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
||||
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
|
||||
capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
|
||||
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
|
||||
capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
|
||||
WPA_DRIVER_AUTH_LEAP;
|
||||
capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_osx_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv;
|
||||
WirelessError err;
|
||||
u8 enabled, power;
|
||||
|
||||
if (!WirelessIsAvailable()) {
|
||||
wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
drv->ctx = ctx;
|
||||
err = WirelessAttach(&drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
|
||||
(int) err);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
err = WirelessGetPower(drv->wireless_ctx, &power);
|
||||
if (err)
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
|
||||
|
||||
if (!enabled) {
|
||||
err = WirelessSetEnabled(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
|
||||
" 0x%08x", (unsigned int) err);
|
||||
WirelessDetach(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!power) {
|
||||
err = WirelessSetPower(drv->wireless_ctx, 1);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
WirelessDetach(drv->wireless_ctx);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_osx_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_osx_data *drv = priv;
|
||||
WirelessError err;
|
||||
|
||||
eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
|
||||
eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
|
||||
|
||||
err = WirelessSetPower(drv->wireless_ctx, 0);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
|
||||
"0x%08x", (unsigned int) err);
|
||||
}
|
||||
|
||||
err = WirelessDetach(drv->wireless_ctx);
|
||||
if (err) {
|
||||
wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
|
||||
(unsigned int) err);
|
||||
}
|
||||
|
||||
if (drv->scan_results)
|
||||
CFRelease(drv->scan_results);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_osx_ops = {
|
||||
.name = "osx",
|
||||
.desc = "Mac OS X Apple80211 driver",
|
||||
.get_ssid = wpa_driver_osx_get_ssid,
|
||||
.get_bssid = wpa_driver_osx_get_bssid,
|
||||
.init = wpa_driver_osx_init,
|
||||
.deinit = wpa_driver_osx_deinit,
|
||||
.scan2 = wpa_driver_osx_scan,
|
||||
.get_scan_results2 = wpa_driver_osx_get_scan_results,
|
||||
.associate = wpa_driver_osx_associate,
|
||||
.set_key = wpa_driver_osx_set_key,
|
||||
.get_capa = wpa_driver_osx_get_capa,
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -1,383 +0,0 @@
|
|||
/*
|
||||
* WPA Supplicant - driver_ralink exported functions
|
||||
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Ralink defined OIDs
|
||||
#if WIRELESS_EXT <= 11
|
||||
#ifndef SIOCDEVPRIVATE
|
||||
#define SIOCDEVPRIVATE 0x8BE0
|
||||
#endif
|
||||
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
|
||||
#endif
|
||||
|
||||
#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
|
||||
#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
|
||||
|
||||
// IEEE 802.11 OIDs & Ralink defined OIDs ******
|
||||
|
||||
// (RaConfig Set/QueryInform) ==>
|
||||
#define OID_GET_SET_TOGGLE 0x8000
|
||||
|
||||
#define OID_802_11_ADD_WEP 0x0112
|
||||
#define OID_802_11_REMOVE_WEP 0x0113
|
||||
#define OID_802_11_DISASSOCIATE 0x0114
|
||||
#define OID_802_11_PRIVACY_FILTER 0x0118
|
||||
#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
|
||||
#define OID_802_11_BSSID_LIST_SCAN 0x0508
|
||||
#define OID_802_11_SSID 0x0509
|
||||
#define OID_802_11_BSSID 0x050A
|
||||
#define OID_802_11_WEP_STATUS 0x0510
|
||||
#define OID_802_11_AUTHENTICATION_MODE 0x0511
|
||||
#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
|
||||
#define OID_802_11_TX_POWER_LEVEL 0x0517
|
||||
#define OID_802_11_REMOVE_KEY 0x0519
|
||||
#define OID_802_11_ADD_KEY 0x0520
|
||||
#define OID_802_11_DEAUTHENTICATION 0x0526
|
||||
#define OID_802_11_DROP_UNENCRYPTED 0x0527
|
||||
#define OID_802_11_BSSID_LIST 0x0609
|
||||
#define OID_802_3_CURRENT_ADDRESS 0x060A
|
||||
#define OID_SET_COUNTERMEASURES 0x0616
|
||||
#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
|
||||
#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
|
||||
#define OID_802_11_PMKID 0x0620
|
||||
#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
|
||||
#define RT_OID_WE_VERSION_COMPILED 0x0622
|
||||
#define RT_OID_NEW_DRIVER 0x0623
|
||||
#define RT_OID_WPS_PROBE_REQ_IE 0x0625
|
||||
|
||||
#define PACKED __attribute__ ((packed))
|
||||
|
||||
//wpa_supplicant event flags
|
||||
#define RT_ASSOC_EVENT_FLAG 0x0101
|
||||
#define RT_DISASSOC_EVENT_FLAG 0x0102
|
||||
#define RT_REQIE_EVENT_FLAG 0x0103
|
||||
#define RT_RESPIE_EVENT_FLAG 0x0104
|
||||
#define RT_ASSOCINFO_EVENT_FLAG 0x0105
|
||||
#define RT_PMKIDCAND_FLAG 0x0106
|
||||
#define RT_INTERFACE_DOWN 0x0107
|
||||
#define RT_INTERFACE_UP 0x0108
|
||||
|
||||
//
|
||||
// IEEE 802.11 Structures and definitions
|
||||
//
|
||||
// new types for Media Specific Indications
|
||||
|
||||
#ifndef ULONG
|
||||
#define CHAR char
|
||||
#define INT int
|
||||
#define SHORT int
|
||||
#define UINT u32
|
||||
#undef ULONG
|
||||
//#define ULONG u32
|
||||
#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
|
||||
#define USHORT unsigned short
|
||||
#define UCHAR unsigned char
|
||||
|
||||
#define uint32 u32
|
||||
#define uint8 u8
|
||||
|
||||
|
||||
#define BOOLEAN u8
|
||||
//#define LARGE_INTEGER s64
|
||||
#define VOID void
|
||||
#define LONG long
|
||||
#define LONGLONG s64
|
||||
#define ULONGLONG u64
|
||||
typedef VOID *PVOID;
|
||||
typedef CHAR *PCHAR;
|
||||
typedef UCHAR *PUCHAR;
|
||||
typedef USHORT *PUSHORT;
|
||||
typedef LONG *PLONG;
|
||||
typedef ULONG *PULONG;
|
||||
|
||||
typedef union _LARGE_INTEGER {
|
||||
struct {
|
||||
ULONG LowPart;
|
||||
LONG HighPart;
|
||||
}vv;
|
||||
struct {
|
||||
ULONG LowPart;
|
||||
LONG HighPart;
|
||||
} u;
|
||||
s64 QuadPart;
|
||||
} LARGE_INTEGER;
|
||||
|
||||
#endif
|
||||
|
||||
#define NDIS_802_11_LENGTH_SSID 32
|
||||
#define NDIS_802_11_LENGTH_RATES 8
|
||||
#define NDIS_802_11_LENGTH_RATES_EX 16
|
||||
#define MAX_LEN_OF_SSID 32
|
||||
#define MAC_ADDR_LEN 6
|
||||
|
||||
typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
|
||||
|
||||
// mask for authentication/integrity fields
|
||||
#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
|
||||
|
||||
#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
|
||||
#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
|
||||
#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
|
||||
#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
|
||||
|
||||
// Added new types for OFDM 5G and 2.4G
|
||||
typedef enum _NDIS_802_11_NETWORK_TYPE
|
||||
{
|
||||
Ndis802_11FH,
|
||||
Ndis802_11DS,
|
||||
Ndis802_11OFDM5,
|
||||
Ndis802_11OFDM24,
|
||||
Ndis802_11Automode,
|
||||
Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
|
||||
} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
|
||||
|
||||
//
|
||||
// Received Signal Strength Indication
|
||||
//
|
||||
typedef LONG NDIS_802_11_RSSI; // in dBm
|
||||
|
||||
typedef struct _NDIS_802_11_CONFIGURATION_FH
|
||||
{
|
||||
ULONG Length; // Length of structure
|
||||
ULONG HopPattern; // As defined by 802.11, MSB set
|
||||
ULONG HopSet; // to one if non-802.11
|
||||
ULONG DwellTime; // units are Kusec
|
||||
} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
|
||||
|
||||
typedef struct _NDIS_802_11_CONFIGURATION
|
||||
{
|
||||
ULONG Length; // Length of structure
|
||||
ULONG BeaconPeriod; // units are Kusec
|
||||
ULONG ATIMWindow; // units are Kusec
|
||||
ULONG DSConfig; // Frequency, units are kHz
|
||||
NDIS_802_11_CONFIGURATION_FH FHConfig;
|
||||
} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
|
||||
|
||||
typedef ULONG NDIS_802_11_KEY_INDEX;
|
||||
typedef ULONGLONG NDIS_802_11_KEY_RSC;
|
||||
|
||||
// Key mapping keys require a BSSID
|
||||
typedef struct _NDIS_802_11_KEY
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex;
|
||||
UINT KeyLength; // length of key in bytes
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
NDIS_802_11_KEY_RSC KeyRSC;
|
||||
UCHAR KeyMaterial[1]; // variable length depending on above field
|
||||
} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
|
||||
|
||||
typedef struct _NDIS_802_11_REMOVE_KEY
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex;
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_WEP
|
||||
{
|
||||
UINT Length; // Length of this structure
|
||||
UINT KeyIndex; // 0 is the per-client key, 1-N are the
|
||||
// global keys
|
||||
UINT KeyLength; // length of key in bytes
|
||||
UCHAR KeyMaterial[1];// variable length depending on above field
|
||||
} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
|
||||
|
||||
|
||||
typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
|
||||
{
|
||||
Ndis802_11IBSS,
|
||||
Ndis802_11Infrastructure,
|
||||
Ndis802_11AutoUnknown,
|
||||
Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
|
||||
} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
|
||||
|
||||
// PMKID Structures
|
||||
typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
|
||||
|
||||
typedef struct _BSSID_INFO
|
||||
{
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
NDIS_802_11_PMKID_VALUE PMKID;
|
||||
} BSSID_INFO, *PBSSID_INFO;
|
||||
|
||||
typedef struct _NDIS_802_11_PMKID
|
||||
{
|
||||
ULONG Length;
|
||||
ULONG BSSIDInfoCount;
|
||||
BSSID_INFO BSSIDInfo[1];
|
||||
} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
|
||||
|
||||
//Added new types for PMKID Candidate lists.
|
||||
typedef struct _PMKID_CANDIDATE {
|
||||
NDIS_802_11_MAC_ADDRESS BSSID;
|
||||
ULONG Flags;
|
||||
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
|
||||
|
||||
typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
|
||||
{
|
||||
ULONG Version; // Version of the structure
|
||||
ULONG NumCandidates; // No. of pmkid candidates
|
||||
PMKID_CANDIDATE CandidateList[1];
|
||||
} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
|
||||
|
||||
//Flags for PMKID Candidate list structure
|
||||
#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
|
||||
|
||||
// Add new authentication modes
|
||||
typedef enum _NDIS_802_11_AUTHENTICATION_MODE
|
||||
{
|
||||
Ndis802_11AuthModeOpen,
|
||||
Ndis802_11AuthModeShared,
|
||||
Ndis802_11AuthModeAutoSwitch,
|
||||
Ndis802_11AuthModeWPA,
|
||||
Ndis802_11AuthModeWPAPSK,
|
||||
Ndis802_11AuthModeWPANone,
|
||||
Ndis802_11AuthModeWPA2,
|
||||
Ndis802_11AuthModeWPA2PSK,
|
||||
Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
|
||||
} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
|
||||
|
||||
typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
|
||||
typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_SSID
|
||||
{
|
||||
INT SsidLength; // length of SSID field below, in bytes;
|
||||
// this can be zero.
|
||||
UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
|
||||
} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
|
||||
|
||||
|
||||
typedef struct PACKED _NDIS_WLAN_BSSID
|
||||
{
|
||||
ULONG Length; // Length of this structure
|
||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
||||
UCHAR Reserved[2];
|
||||
NDIS_802_11_SSID Ssid; // SSID
|
||||
ULONG Privacy; // WEP encryption requirement
|
||||
NDIS_802_11_RSSI Rssi; // receive signal
|
||||
// strength in dBm
|
||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
||||
NDIS_802_11_CONFIGURATION Configuration;
|
||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
||||
NDIS_802_11_RATES SupportedRates;
|
||||
} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST
|
||||
{
|
||||
UINT NumberOfItems; // in list below, at least 1
|
||||
NDIS_WLAN_BSSID Bssid[1];
|
||||
} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
|
||||
|
||||
// Added Capabilities, IELength and IEs for each BSSID
|
||||
typedef struct PACKED _NDIS_WLAN_BSSID_EX
|
||||
{
|
||||
ULONG Length; // Length of this structure
|
||||
NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
|
||||
UCHAR Reserved[2];
|
||||
NDIS_802_11_SSID Ssid; // SSID
|
||||
UINT Privacy; // WEP encryption requirement
|
||||
NDIS_802_11_RSSI Rssi; // receive signal
|
||||
// strength in dBm
|
||||
NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
|
||||
NDIS_802_11_CONFIGURATION Configuration;
|
||||
NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
|
||||
NDIS_802_11_RATES_EX SupportedRates;
|
||||
ULONG IELength;
|
||||
UCHAR IEs[1];
|
||||
} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
|
||||
{
|
||||
UINT NumberOfItems; // in list below, at least 1
|
||||
NDIS_WLAN_BSSID_EX Bssid[1];
|
||||
} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
|
||||
|
||||
typedef struct PACKED _NDIS_802_11_FIXED_IEs
|
||||
{
|
||||
UCHAR Timestamp[8];
|
||||
USHORT BeaconInterval;
|
||||
USHORT Capabilities;
|
||||
} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
|
||||
|
||||
// Added new encryption types
|
||||
// Also aliased typedef to new name
|
||||
typedef enum _NDIS_802_11_WEP_STATUS
|
||||
{
|
||||
Ndis802_11WEPEnabled,
|
||||
Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
|
||||
Ndis802_11WEPDisabled,
|
||||
Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
|
||||
Ndis802_11WEPKeyAbsent,
|
||||
Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
|
||||
Ndis802_11WEPNotSupported,
|
||||
Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
|
||||
Ndis802_11Encryption2Enabled,
|
||||
Ndis802_11Encryption2KeyAbsent,
|
||||
Ndis802_11Encryption3Enabled,
|
||||
Ndis802_11Encryption3KeyAbsent
|
||||
} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
|
||||
NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
|
||||
|
||||
typedef enum _NDIS_802_11_RELOAD_DEFAULTS
|
||||
{
|
||||
Ndis802_11ReloadWEPKeys
|
||||
} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
|
||||
|
||||
#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
|
||||
#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
|
||||
#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
|
||||
|
||||
#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
|
||||
#define NDIS_802_11_AI_RESFI_STATUSCODE 2
|
||||
#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
|
||||
|
||||
typedef struct _NDIS_802_11_AI_REQFI
|
||||
{
|
||||
USHORT Capabilities;
|
||||
USHORT ListenInterval;
|
||||
NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
|
||||
} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
|
||||
|
||||
typedef struct _NDIS_802_11_AI_RESFI
|
||||
{
|
||||
USHORT Capabilities;
|
||||
USHORT StatusCode;
|
||||
USHORT AssociationId;
|
||||
} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
|
||||
|
||||
typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
|
||||
{
|
||||
ULONG Length;
|
||||
USHORT AvailableRequestFixedIEs;
|
||||
NDIS_802_11_AI_REQFI RequestFixedIEs;
|
||||
ULONG RequestIELength;
|
||||
ULONG OffsetRequestIEs;
|
||||
USHORT AvailableResponseFixedIEs;
|
||||
NDIS_802_11_AI_RESFI ResponseFixedIEs;
|
||||
ULONG ResponseIELength;
|
||||
ULONG OffsetResponseIEs;
|
||||
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
|
||||
|
||||
struct ndis_pmkid_entry {
|
||||
struct ndis_pmkid_entry *next;
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 pmkid[16];
|
||||
};
|
||||
|
||||
typedef struct _MLME_DEAUTH_REQ_STRUCT {
|
||||
UCHAR Addr[MAC_ADDR_LEN];
|
||||
USHORT Reason;
|
||||
} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
|
File diff suppressed because it is too large
Load diff
|
@ -1,629 +0,0 @@
|
|||
/*
|
||||
* Wired Ethernet driver interface
|
||||
* Copyright (c) 2005-2009, 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>
|
||||
#include <net/if.h>
|
||||
#ifdef __linux__
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if.h>
|
||||
#endif /* __linux__ */
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
||||
#include <net/if_dl.h>
|
||||
#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
|
||||
#ifdef __sun__
|
||||
#include <sys/sockio.h>
|
||||
#endif /* __sun__ */
|
||||
|
||||
#include "common.h"
|
||||
#include "eloop.h"
|
||||
#include "driver.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
struct ieee8023_hdr {
|
||||
u8 dest[6];
|
||||
u8 src[6];
|
||||
u16 ethertype;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
static const u8 pae_group_addr[ETH_ALEN] =
|
||||
{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
|
||||
|
||||
|
||||
struct wpa_driver_wired_data {
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
void *ctx;
|
||||
|
||||
int sock; /* raw packet socket for driver access */
|
||||
int dhcp_sock; /* socket for dhcp packets */
|
||||
int use_pae_group_addr;
|
||||
|
||||
int pf_sock;
|
||||
int membership, multi, iff_allmulti, iff_up;
|
||||
};
|
||||
|
||||
|
||||
/* 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 int wired_multicast_membership(int sock, int ifindex,
|
||||
const u8 *addr, int add)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct packet_mreq mreq;
|
||||
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
os_memset(&mreq, 0, sizeof(mreq));
|
||||
mreq.mr_ifindex = ifindex;
|
||||
mreq.mr_type = PACKET_MR_MULTICAST;
|
||||
mreq.mr_alen = ETH_ALEN;
|
||||
os_memcpy(mreq.mr_address, addr, ETH_ALEN);
|
||||
|
||||
if (setsockopt(sock, SOL_PACKET,
|
||||
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
|
||||
&mreq, sizeof(mreq)) < 0) {
|
||||
perror("setsockopt");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#else /* __linux__ */
|
||||
return -1;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
static void handle_data(void *ctx, unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef HOSTAPD
|
||||
struct ieee8023_hdr *hdr;
|
||||
u8 *pos, *sa;
|
||||
size_t left;
|
||||
union wpa_event_data event;
|
||||
|
||||
/* 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;
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.new_sta.addr = sa;
|
||||
wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
left = len - sizeof(*hdr);
|
||||
drv_event_eapol_rx(ctx, sa, pos, left);
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
|
||||
ntohs(hdr->ethertype));
|
||||
break;
|
||||
}
|
||||
#endif /* HOSTAPD */
|
||||
}
|
||||
|
||||
|
||||
static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[3000];
|
||||
|
||||
len = recv(sock, buf, sizeof(buf), 0);
|
||||
if (len < 0) {
|
||||
perror("recv");
|
||||
return;
|
||||
}
|
||||
|
||||
handle_data(eloop_ctx, buf, len);
|
||||
}
|
||||
|
||||
|
||||
static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
int len;
|
||||
unsigned char buf[3000];
|
||||
struct dhcp_message *msg;
|
||||
u8 *mac_address;
|
||||
union wpa_event_data event;
|
||||
|
||||
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));
|
||||
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.new_sta.addr = mac_address;
|
||||
wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event);
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
|
||||
static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr)
|
||||
{
|
||||
#ifdef __linux__
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_ll addr;
|
||||
struct sockaddr_in addr2;
|
||||
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, drv->ctx, NULL)) {
|
||||
printf("Could not register read socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
|
||||
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||
perror("ioctl(SIOCGIFINDEX)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_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 */
|
||||
if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
|
||||
pae_group_addr, 1) < 0) {
|
||||
wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
|
||||
"membership");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, drv->ifname, 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;
|
||||
}
|
||||
os_memcpy(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, drv->ctx,
|
||||
NULL)) {
|
||||
printf("Could not register read socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_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;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, 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;
|
||||
#else /* __linux__ */
|
||||
return -1;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
static int wired_send_eapol(void *priv, const u8 *addr,
|
||||
const u8 *data, size_t data_len, int encrypt,
|
||||
const u8 *own_addr, u32 flags)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv = priv;
|
||||
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;
|
||||
}
|
||||
|
||||
os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hdr->src, own_addr, ETH_ALEN);
|
||||
hdr->ethertype = htons(ETH_P_PAE);
|
||||
|
||||
pos = (u8 *) (hdr + 1);
|
||||
os_memcpy(pos, data, data_len);
|
||||
|
||||
res = send(drv->sock, (u8 *) hdr, len, 0);
|
||||
os_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_hapd_init(struct hostapd_data *hapd,
|
||||
struct wpa_init_params *params)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv;
|
||||
|
||||
drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
|
||||
if (drv == NULL) {
|
||||
printf("Could not allocate memory for wired driver data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drv->ctx = hapd;
|
||||
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
|
||||
drv->use_pae_group_addr = params->use_pae_group_addr;
|
||||
|
||||
if (wired_init_sockets(drv, params->own_addr)) {
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wired_driver_hapd_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv = priv;
|
||||
|
||||
if (drv->sock >= 0)
|
||||
close(drv->sock);
|
||||
|
||||
if (drv->dhcp_sock >= 0)
|
||||
close(drv->dhcp_sock);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
|
||||
{
|
||||
ssid[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
|
||||
{
|
||||
/* Report PAE group address as the "BSSID" for wired connection. */
|
||||
os_memcpy(bssid, pae_group_addr, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
|
||||
{
|
||||
os_memset(capa, 0, sizeof(*capa));
|
||||
capa->flags = WPA_DRIVER_FLAGS_WIRED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOCGIFFLAGS]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
*flags = ifr.ifr_flags & 0xffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
ifr.ifr_flags = flags & 0xffff;
|
||||
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOCSIFFLAGS]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
#ifdef __sun__
|
||||
return -1;
|
||||
#endif /* __sun__ */
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
#ifdef __linux__
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
|
||||
#endif /* __linux__ */
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
||||
{
|
||||
struct sockaddr_dl *dlp;
|
||||
dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
|
||||
dlp->sdl_len = sizeof(struct sockaddr_dl);
|
||||
dlp->sdl_family = AF_LINK;
|
||||
dlp->sdl_index = 0;
|
||||
dlp->sdl_nlen = 0;
|
||||
dlp->sdl_alen = ETH_ALEN;
|
||||
dlp->sdl_slen = 0;
|
||||
os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
|
||||
}
|
||||
#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
|
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
|
||||
{
|
||||
struct sockaddr *sap;
|
||||
sap = (struct sockaddr *) &ifr.ifr_addr;
|
||||
sap->sa_len = sizeof(struct sockaddr);
|
||||
sap->sa_family = AF_UNSPEC;
|
||||
os_memcpy(sap->sa_data, addr, ETH_ALEN);
|
||||
}
|
||||
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
|
||||
|
||||
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
|
||||
perror("ioctl[SIOC{ADD/DEL}MULTI]");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv;
|
||||
int flags;
|
||||
|
||||
drv = os_zalloc(sizeof(*drv));
|
||||
if (drv == NULL)
|
||||
return NULL;
|
||||
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
|
||||
drv->ctx = ctx;
|
||||
|
||||
#ifdef __linux__
|
||||
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||||
if (drv->pf_sock < 0)
|
||||
perror("socket(PF_PACKET)");
|
||||
#else /* __linux__ */
|
||||
drv->pf_sock = -1;
|
||||
#endif /* __linux__ */
|
||||
|
||||
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
|
||||
!(flags & IFF_UP) &&
|
||||
wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
|
||||
drv->iff_up = 1;
|
||||
}
|
||||
|
||||
if (wired_multicast_membership(drv->pf_sock,
|
||||
if_nametoindex(drv->ifname),
|
||||
pae_group_addr, 1) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
|
||||
"packet socket", __func__);
|
||||
drv->membership = 1;
|
||||
} else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
|
||||
"SIOCADDMULTI", __func__);
|
||||
drv->multi = 1;
|
||||
} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Could not get interface "
|
||||
"flags", __func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
} else if (flags & IFF_ALLMULTI) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
|
||||
"for multicast", __func__);
|
||||
} else if (wpa_driver_wired_set_ifflags(ifname,
|
||||
flags | IFF_ALLMULTI) < 0) {
|
||||
wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
|
||||
__func__);
|
||||
os_free(drv);
|
||||
return NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
|
||||
__func__);
|
||||
drv->iff_allmulti = 1;
|
||||
}
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
|
||||
static void wpa_driver_wired_deinit(void *priv)
|
||||
{
|
||||
struct wpa_driver_wired_data *drv = priv;
|
||||
int flags;
|
||||
|
||||
if (drv->membership &&
|
||||
wired_multicast_membership(drv->pf_sock,
|
||||
if_nametoindex(drv->ifname),
|
||||
pae_group_addr, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
|
||||
"group (PACKET)", __func__);
|
||||
}
|
||||
|
||||
if (drv->multi &&
|
||||
wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
|
||||
"group (SIOCDELMULTI)", __func__);
|
||||
}
|
||||
|
||||
if (drv->iff_allmulti &&
|
||||
(wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
|
||||
wpa_driver_wired_set_ifflags(drv->ifname,
|
||||
flags & ~IFF_ALLMULTI) < 0)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (drv->iff_up &&
|
||||
wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
|
||||
(flags & IFF_UP) &&
|
||||
wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
|
||||
__func__);
|
||||
}
|
||||
|
||||
if (drv->pf_sock != -1)
|
||||
close(drv->pf_sock);
|
||||
|
||||
os_free(drv);
|
||||
}
|
||||
|
||||
|
||||
const struct wpa_driver_ops wpa_driver_wired_ops = {
|
||||
.name = "wired",
|
||||
.desc = "Wired Ethernet driver",
|
||||
.hapd_init = wired_driver_hapd_init,
|
||||
.hapd_deinit = wired_driver_hapd_deinit,
|
||||
.hapd_send_eapol = wired_send_eapol,
|
||||
.get_ssid = wpa_driver_wired_get_ssid,
|
||||
.get_bssid = wpa_driver_wired_get_bssid,
|
||||
.get_capa = wpa_driver_wired_get_capa,
|
||||
.init = wpa_driver_wired_init,
|
||||
.deinit = wpa_driver_wired_deinit,
|
||||
};
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Driver interface list
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_DRIVER_WEXT
|
||||
extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
|
||||
#endif /* CONFIG_DRIVER_WEXT */
|
||||
#ifdef CONFIG_DRIVER_NL80211
|
||||
extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
|
||||
#endif /* CONFIG_DRIVER_NL80211 */
|
||||
#ifdef CONFIG_DRIVER_HOSTAP
|
||||
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
|
||||
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||
#ifdef CONFIG_DRIVER_MADWIFI
|
||||
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
|
||||
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||
#ifdef CONFIG_DRIVER_BROADCOM
|
||||
extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
|
||||
#endif /* CONFIG_DRIVER_BROADCOM */
|
||||
#ifdef CONFIG_DRIVER_BSD
|
||||
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
|
||||
#endif /* CONFIG_DRIVER_BSD */
|
||||
#ifdef CONFIG_DRIVER_NDIS
|
||||
extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
|
||||
#endif /* CONFIG_DRIVER_NDIS */
|
||||
#ifdef CONFIG_DRIVER_WIRED
|
||||
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
|
||||
#endif /* CONFIG_DRIVER_WIRED */
|
||||
#ifdef CONFIG_DRIVER_TEST
|
||||
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
|
||||
#endif /* CONFIG_DRIVER_TEST */
|
||||
#ifdef CONFIG_DRIVER_RALINK
|
||||
extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
|
||||
#endif /* CONFIG_DRIVER_RALINK */
|
||||
#ifdef CONFIG_DRIVER_OSX
|
||||
extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
|
||||
#endif /* CONFIG_DRIVER_OSX */
|
||||
#ifdef CONFIG_DRIVER_IPHONE
|
||||
extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
|
||||
#endif /* CONFIG_DRIVER_IPHONE */
|
||||
#ifdef CONFIG_DRIVER_ROBOSWITCH
|
||||
/* driver_roboswitch.c */
|
||||
extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
|
||||
#endif /* CONFIG_DRIVER_ROBOSWITCH */
|
||||
#ifdef CONFIG_DRIVER_ATHEROS
|
||||
extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
|
||||
#endif /* CONFIG_DRIVER_ATHEROS */
|
||||
#ifdef CONFIG_DRIVER_NONE
|
||||
extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
|
||||
#endif /* CONFIG_DRIVER_NONE */
|
||||
#ifdef CONFIG_DRIVER_RTW
|
||||
extern struct wpa_driver_ops wpa_driver_rtw_ops; /* driver_rtw.c */
|
||||
#endif /* CONFIG_DRIVER_RTW */
|
||||
|
||||
|
||||
struct wpa_driver_ops *wpa_drivers[] =
|
||||
{
|
||||
#ifdef CONFIG_DRIVER_WEXT
|
||||
&wpa_driver_wext_ops,
|
||||
#endif /* CONFIG_DRIVER_WEXT */
|
||||
#ifdef CONFIG_DRIVER_NL80211
|
||||
&wpa_driver_nl80211_ops,
|
||||
#endif /* CONFIG_DRIVER_NL80211 */
|
||||
#ifdef CONFIG_DRIVER_HOSTAP
|
||||
&wpa_driver_hostap_ops,
|
||||
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||
#ifdef CONFIG_DRIVER_MADWIFI
|
||||
&wpa_driver_madwifi_ops,
|
||||
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||
#ifdef CONFIG_DRIVER_BROADCOM
|
||||
&wpa_driver_broadcom_ops,
|
||||
#endif /* CONFIG_DRIVER_BROADCOM */
|
||||
#ifdef CONFIG_DRIVER_BSD
|
||||
&wpa_driver_bsd_ops,
|
||||
#endif /* CONFIG_DRIVER_BSD */
|
||||
#ifdef CONFIG_DRIVER_NDIS
|
||||
&wpa_driver_ndis_ops,
|
||||
#endif /* CONFIG_DRIVER_NDIS */
|
||||
#ifdef CONFIG_DRIVER_WIRED
|
||||
&wpa_driver_wired_ops,
|
||||
#endif /* CONFIG_DRIVER_WIRED */
|
||||
#ifdef CONFIG_DRIVER_TEST
|
||||
&wpa_driver_test_ops,
|
||||
#endif /* CONFIG_DRIVER_TEST */
|
||||
#ifdef CONFIG_DRIVER_RALINK
|
||||
&wpa_driver_ralink_ops,
|
||||
#endif /* CONFIG_DRIVER_RALINK */
|
||||
#ifdef CONFIG_DRIVER_OSX
|
||||
&wpa_driver_osx_ops,
|
||||
#endif /* CONFIG_DRIVER_OSX */
|
||||
#ifdef CONFIG_DRIVER_IPHONE
|
||||
&wpa_driver_iphone_ops,
|
||||
#endif /* CONFIG_DRIVER_IPHONE */
|
||||
#ifdef CONFIG_DRIVER_ROBOSWITCH
|
||||
&wpa_driver_roboswitch_ops,
|
||||
#endif /* CONFIG_DRIVER_ROBOSWITCH */
|
||||
#ifdef CONFIG_DRIVER_ATHEROS
|
||||
&wpa_driver_atheros_ops,
|
||||
#endif /* CONFIG_DRIVER_ATHEROS */
|
||||
#ifdef CONFIG_DRIVER_NONE
|
||||
&wpa_driver_none_ops,
|
||||
#endif /* CONFIG_DRIVER_NONE */
|
||||
#ifdef CONFIG_DRIVER_RTW
|
||||
&wpa_driver_rtw_ops,
|
||||
#endif /* CONFIG_DRIVER_RTW */
|
||||
NULL
|
||||
};
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* CHAP-MD5 (RFC 1994)
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef CHAP_H
|
||||
#define CHAP_H
|
||||
|
||||
#define CHAP_MD5_LEN 16
|
||||
|
||||
int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
|
||||
size_t challenge_len, u8 *response);
|
||||
|
||||
#endif /* CHAP_H */
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* EAP-PEAP common routines
|
||||
* 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 EAP_PEAP_COMMON_H
|
||||
#define EAP_PEAP_COMMON_H
|
||||
|
||||
void peap_prfplus(int version, const u8 *key, size_t key_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *buf, size_t buf_len);
|
||||
|
||||
#endif /* EAP_PEAP_COMMON_H */
|
|
@ -1,312 +0,0 @@
|
|||
/*
|
||||
* EAP server/peer: EAP-pwd shared routines
|
||||
* Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the BSD license.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "common.h"
|
||||
#include "eap_defs.h"
|
||||
#include "eap_pwd_common.h"
|
||||
|
||||
/* The random function H(x) = HMAC-SHA256(0^32, x) */
|
||||
void H_Init(HMAC_CTX *ctx)
|
||||
{
|
||||
u8 allzero[SHA256_DIGEST_LENGTH];
|
||||
|
||||
os_memset(allzero, 0, SHA256_DIGEST_LENGTH);
|
||||
HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
|
||||
}
|
||||
|
||||
|
||||
void H_Update(HMAC_CTX *ctx, const u8 *data, int len)
|
||||
{
|
||||
HMAC_Update(ctx, data, len);
|
||||
}
|
||||
|
||||
|
||||
void H_Final(HMAC_CTX *ctx, u8 *digest)
|
||||
{
|
||||
unsigned int mdlen = SHA256_DIGEST_LENGTH;
|
||||
|
||||
HMAC_Final(ctx, digest, &mdlen);
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
}
|
||||
|
||||
|
||||
/* a counter-based KDF based on NIST SP800-108 */
|
||||
void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen,
|
||||
u8 *result, int resultbitlen)
|
||||
{
|
||||
HMAC_CTX hctx;
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
u16 i, ctr, L;
|
||||
int resultbytelen, len = 0;
|
||||
unsigned int mdlen = SHA256_DIGEST_LENGTH;
|
||||
unsigned char mask = 0xff;
|
||||
|
||||
resultbytelen = (resultbitlen + 7)/8;
|
||||
ctr = 0;
|
||||
L = htons(resultbitlen);
|
||||
while (len < resultbytelen) {
|
||||
ctr++; i = htons(ctr);
|
||||
HMAC_Init(&hctx, key, keylen, EVP_sha256());
|
||||
if (ctr > 1)
|
||||
HMAC_Update(&hctx, digest, mdlen);
|
||||
HMAC_Update(&hctx, (u8 *) &i, sizeof(u16));
|
||||
HMAC_Update(&hctx, label, labellen);
|
||||
HMAC_Update(&hctx, (u8 *) &L, sizeof(u16));
|
||||
HMAC_Final(&hctx, digest, &mdlen);
|
||||
if ((len + (int) mdlen) > resultbytelen)
|
||||
os_memcpy(result + len, digest, resultbytelen - len);
|
||||
else
|
||||
os_memcpy(result + len, digest, mdlen);
|
||||
len += mdlen;
|
||||
HMAC_CTX_cleanup(&hctx);
|
||||
}
|
||||
|
||||
/* since we're expanding to a bit length, mask off the excess */
|
||||
if (resultbitlen % 8) {
|
||||
mask >>= ((resultbytelen * 8) - resultbitlen);
|
||||
result[0] &= mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compute a "random" secret point on an elliptic curve based
|
||||
* on the password and identities.
|
||||
*/
|
||||
int compute_password_element(EAP_PWD_group *grp, u16 num,
|
||||
u8 *password, int password_len,
|
||||
u8 *id_server, int id_server_len,
|
||||
u8 *id_peer, int id_peer_len, u8 *token)
|
||||
{
|
||||
BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
|
||||
HMAC_CTX ctx;
|
||||
unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
|
||||
int nid, is_odd, primebitlen, primebytelen, ret = 0;
|
||||
|
||||
switch (num) { /* from IANA registry for IKE D-H groups */
|
||||
case 19:
|
||||
nid = NID_X9_62_prime256v1;
|
||||
break;
|
||||
case 20:
|
||||
nid = NID_secp384r1;
|
||||
break;
|
||||
case 21:
|
||||
nid = NID_secp521r1;
|
||||
break;
|
||||
case 25:
|
||||
nid = NID_X9_62_prime192v1;
|
||||
break;
|
||||
case 26:
|
||||
nid = NID_secp224r1;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
grp->pwe = NULL;
|
||||
grp->order = NULL;
|
||||
grp->prime = NULL;
|
||||
|
||||
if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (((rnd = BN_new()) == NULL) ||
|
||||
((cofactor = BN_new()) == NULL) ||
|
||||
((grp->pwe = EC_POINT_new(grp->group)) == NULL) ||
|
||||
((grp->order = BN_new()) == NULL) ||
|
||||
((grp->prime = BN_new()) == NULL) ||
|
||||
((x_candidate = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL))
|
||||
{
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp "
|
||||
"curve");
|
||||
goto fail;
|
||||
}
|
||||
if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve");
|
||||
goto fail;
|
||||
}
|
||||
if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for "
|
||||
"curve");
|
||||
goto fail;
|
||||
}
|
||||
primebitlen = BN_num_bits(grp->prime);
|
||||
primebytelen = BN_num_bytes(grp->prime);
|
||||
if ((prfbuf = os_malloc(primebytelen)) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf "
|
||||
"buffer");
|
||||
goto fail;
|
||||
}
|
||||
os_memset(prfbuf, 0, primebytelen);
|
||||
ctr = 0;
|
||||
while (1) {
|
||||
if (ctr > 10) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: unable to find random "
|
||||
"point on curve for group %d, something's "
|
||||
"fishy", num);
|
||||
goto fail;
|
||||
}
|
||||
ctr++;
|
||||
|
||||
/*
|
||||
* compute counter-mode password value and stretch to prime
|
||||
* pwd-seed = H(token | peer-id | server-id | password |
|
||||
* counter)
|
||||
*/
|
||||
H_Init(&ctx);
|
||||
H_Update(&ctx, token, sizeof(u32));
|
||||
H_Update(&ctx, id_peer, id_peer_len);
|
||||
H_Update(&ctx, id_server, id_server_len);
|
||||
H_Update(&ctx, password, password_len);
|
||||
H_Update(&ctx, &ctr, sizeof(ctr));
|
||||
H_Final(&ctx, pwe_digest);
|
||||
|
||||
BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
|
||||
|
||||
eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
|
||||
(unsigned char *) "EAP-pwd Hunting And Pecking",
|
||||
os_strlen("EAP-pwd Hunting And Pecking"),
|
||||
prfbuf, primebitlen);
|
||||
|
||||
BN_bin2bn(prfbuf, primebytelen, x_candidate);
|
||||
if (BN_ucmp(x_candidate, grp->prime) >= 0)
|
||||
continue;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate",
|
||||
prfbuf, primebytelen);
|
||||
|
||||
/*
|
||||
* need to unambiguously identify the solution, if there is
|
||||
* one...
|
||||
*/
|
||||
if (BN_is_odd(rnd))
|
||||
is_odd = 1;
|
||||
else
|
||||
is_odd = 0;
|
||||
|
||||
/*
|
||||
* solve the quadratic equation, if it's not solvable then we
|
||||
* don't have a point
|
||||
*/
|
||||
if (!EC_POINT_set_compressed_coordinates_GFp(grp->group,
|
||||
grp->pwe,
|
||||
x_candidate,
|
||||
is_odd, NULL))
|
||||
continue;
|
||||
/*
|
||||
* If there's a solution to the equation then the point must be
|
||||
* on the curve so why check again explicitly? OpenSSL code
|
||||
* says this is required by X9.62. We're not X9.62 but it can't
|
||||
* hurt just to be sure.
|
||||
*/
|
||||
if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BN_cmp(cofactor, BN_value_one())) {
|
||||
/* make sure the point is not in a small sub-group */
|
||||
if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe,
|
||||
cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: cannot "
|
||||
"multiply generator by order");
|
||||
continue;
|
||||
}
|
||||
if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: point is at "
|
||||
"infinity");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* if we got here then we have a new generator. */
|
||||
break;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr);
|
||||
grp->group_num = num;
|
||||
if (0) {
|
||||
fail:
|
||||
EC_GROUP_free(grp->group);
|
||||
EC_POINT_free(grp->pwe);
|
||||
BN_free(grp->order);
|
||||
BN_free(grp->prime);
|
||||
os_free(grp);
|
||||
grp = NULL;
|
||||
ret = 1;
|
||||
}
|
||||
/* cleanliness and order.... */
|
||||
BN_free(cofactor);
|
||||
BN_free(x_candidate);
|
||||
BN_free(rnd);
|
||||
os_free(prfbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k,
|
||||
BIGNUM *peer_scalar, BIGNUM *server_scalar,
|
||||
u8 *commit_peer, u8 *commit_server,
|
||||
u32 *ciphersuite, u8 *msk, u8 *emsk)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
u8 mk[SHA256_DIGEST_LENGTH], *cruft;
|
||||
u8 session_id[SHA256_DIGEST_LENGTH + 1];
|
||||
u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
|
||||
|
||||
if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* first compute the session-id = TypeCode | H(ciphersuite | scal_p |
|
||||
* scal_s)
|
||||
*/
|
||||
session_id[0] = EAP_TYPE_PWD;
|
||||
H_Init(&ctx);
|
||||
H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
|
||||
BN_bn2bin(peer_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(grp->order));
|
||||
BN_bn2bin(server_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(grp->order));
|
||||
H_Final(&ctx, &session_id[1]);
|
||||
|
||||
/* then compute MK = H(k | commit-peer | commit-server) */
|
||||
H_Init(&ctx);
|
||||
os_memset(cruft, 0, BN_num_bytes(grp->prime));
|
||||
BN_bn2bin(k, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
|
||||
H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH);
|
||||
H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH);
|
||||
H_Final(&ctx, mk);
|
||||
|
||||
/* stretch the mk with the session-id to get MSK | EMSK */
|
||||
eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
|
||||
session_id, SHA256_DIGEST_LENGTH+1,
|
||||
msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8);
|
||||
|
||||
os_memcpy(msk, msk_emsk, EAP_MSK_LEN);
|
||||
os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN);
|
||||
|
||||
os_free(cruft);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* EAP server/peer: EAP-pwd shared definitions
|
||||
* Copyright (c) 2009, Dan Harkins <dharkins@lounge.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the BSD license.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_PWD_COMMON_H
|
||||
#define EAP_PWD_COMMON_H
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
/*
|
||||
* definition of a finite cyclic group
|
||||
* TODO: support one based on a prime field
|
||||
*/
|
||||
typedef struct group_definition_ {
|
||||
u16 group_num;
|
||||
EC_GROUP *group;
|
||||
EC_POINT *pwe;
|
||||
BIGNUM *order;
|
||||
BIGNUM *prime;
|
||||
} EAP_PWD_group;
|
||||
|
||||
/*
|
||||
* EAP-pwd header, included on all payloads
|
||||
*/
|
||||
struct eap_pwd_hdr {
|
||||
u8 l_bit:1;
|
||||
u8 m_bit:1;
|
||||
u8 exch:6;
|
||||
u8 total_length[0]; /* included when l_bit is set */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define EAP_PWD_OPCODE_ID_EXCH 1
|
||||
#define EAP_PWD_OPCODE_COMMIT_EXCH 2
|
||||
#define EAP_PWD_OPCODE_CONFIRM_EXCH 3
|
||||
#define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exch & 0x80)
|
||||
#define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exch |= 0x80)
|
||||
#define EAP_PWD_GET_MORE_BIT(x) ((x)->lm_exch & 0x40)
|
||||
#define EAP_PWD_SET_MORE_BIT(x) ((x)->lm_exch |= 0x40)
|
||||
#define EAP_PWD_GET_EXCHANGE(x) ((x)->lm_exch & 0x3f)
|
||||
#define EAP_PWD_SET_EXCHANGE(x,y) ((x)->lm_exch |= (y))
|
||||
|
||||
/* EAP-pwd-ID payload */
|
||||
struct eap_pwd_id {
|
||||
be16 group_num;
|
||||
u8 random_function;
|
||||
#define EAP_PWD_DEFAULT_RAND_FUNC 1
|
||||
u8 prf;
|
||||
#define EAP_PWD_DEFAULT_PRF 1
|
||||
u8 token[4];
|
||||
u8 prep;
|
||||
#define EAP_PWD_PREP_NONE 0
|
||||
#define EAP_PWD_PREP_MS 1
|
||||
u8 identity[0]; /* length inferred from payload */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* common routines */
|
||||
int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
|
||||
int, u8 *);
|
||||
int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *,
|
||||
u8 *, u8 *, u32 *, u8 *, u8 *);
|
||||
void H_Init(HMAC_CTX *);
|
||||
void H_Update(HMAC_CTX *, const u8 *, int);
|
||||
void H_Final(HMAC_CTX *, u8 *);
|
||||
|
||||
#endif /* EAP_PWD_COMMON_H */
|
|
@ -1,11 +0,0 @@
|
|||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.so *.d
|
||||
|
||||
install:
|
||||
if ls *.so >/dev/null 2>&1; then \
|
||||
install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \
|
||||
cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \
|
||||
; fi
|
|
@ -1,744 +0,0 @@
|
|||
/*
|
||||
* EAP peer method: EAP-pwd (RFC 5931)
|
||||
* Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the BSD license.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_peer/eap_i.h"
|
||||
#include "eap_common/eap_pwd_common.h"
|
||||
|
||||
|
||||
struct eap_pwd_data {
|
||||
enum {
|
||||
PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
|
||||
} state;
|
||||
u8 *id_peer;
|
||||
size_t id_peer_len;
|
||||
u8 *id_server;
|
||||
size_t id_server_len;
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
u16 group_num;
|
||||
EAP_PWD_group *grp;
|
||||
|
||||
BIGNUM *k;
|
||||
BIGNUM *private_value;
|
||||
BIGNUM *server_scalar;
|
||||
BIGNUM *my_scalar;
|
||||
EC_POINT *my_element;
|
||||
EC_POINT *server_element;
|
||||
|
||||
u8 msk[EAP_MSK_LEN];
|
||||
u8 emsk[EAP_EMSK_LEN];
|
||||
|
||||
BN_CTX *bnctx;
|
||||
};
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
static const char * eap_pwd_state_txt(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case PWD_ID_Req:
|
||||
return "PWD-ID-Req";
|
||||
case PWD_Commit_Req:
|
||||
return "PWD-Commit-Req";
|
||||
case PWD_Confirm_Req:
|
||||
return "PWD-Confirm-Req";
|
||||
case SUCCESS:
|
||||
return "SUCCESS";
|
||||
case FAILURE:
|
||||
return "FAILURE";
|
||||
default:
|
||||
return "PWD-UNK";
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
static void eap_pwd_state(struct eap_pwd_data *data, int state)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: %s -> %s",
|
||||
eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
|
||||
data->state = state;
|
||||
}
|
||||
|
||||
|
||||
static void * eap_pwd_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_pwd_data *data;
|
||||
const u8 *identity, *password;
|
||||
size_t identity_len, password_len;
|
||||
|
||||
password = eap_get_config_password(sm, &password_len);
|
||||
if (password == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: No password configured!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
if (identity == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((data = os_zalloc(sizeof(*data))) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((data->bnctx = BN_CTX_new()) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((data->id_peer = os_malloc(identity_len)) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
|
||||
BN_CTX_free(data->bnctx);
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memcpy(data->id_peer, identity, identity_len);
|
||||
data->id_peer_len = identity_len;
|
||||
|
||||
if ((data->password = os_malloc(password_len)) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
|
||||
BN_CTX_free(data->bnctx);
|
||||
os_free(data->id_peer);
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
os_memcpy(data->password, password, password_len);
|
||||
data->password_len = password_len;
|
||||
|
||||
data->state = PWD_ID_Req;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pwd_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
|
||||
BN_free(data->private_value);
|
||||
BN_free(data->server_scalar);
|
||||
BN_free(data->my_scalar);
|
||||
BN_free(data->k);
|
||||
BN_CTX_free(data->bnctx);
|
||||
EC_POINT_free(data->my_element);
|
||||
EC_POINT_free(data->server_element);
|
||||
os_free(data->id_peer);
|
||||
os_free(data->id_server);
|
||||
os_free(data->password);
|
||||
if (data->grp) {
|
||||
EC_GROUP_free(data->grp->group);
|
||||
EC_POINT_free(data->grp->pwe);
|
||||
BN_free(data->grp->order);
|
||||
BN_free(data->grp->prime);
|
||||
os_free(data->grp);
|
||||
}
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_MSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
os_memcpy(key, data->msk, EAP_MSK_LEN);
|
||||
*len = EAP_MSK_LEN;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
struct eap_pwd_id *id;
|
||||
struct wpabuf *resp;
|
||||
|
||||
if (data->state != PWD_ID_Req) {
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (payload_len < sizeof(struct eap_pwd_id)) {
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = (struct eap_pwd_id *) payload;
|
||||
data->group_num = be_to_host16(id->group_num);
|
||||
if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
|
||||
(id->prf != EAP_PWD_DEFAULT_PRF)) {
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-PWD (peer): server said group %d",
|
||||
data->group_num);
|
||||
|
||||
data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id));
|
||||
if (data->id_server == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
|
||||
return NULL;
|
||||
}
|
||||
data->id_server_len = payload_len - sizeof(struct eap_pwd_id);
|
||||
os_memcpy(data->id_server, id->identity, data->id_server_len);
|
||||
wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of",
|
||||
data->id_server, data->id_server_len);
|
||||
|
||||
if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) ==
|
||||
NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
|
||||
"group");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* compute PWE */
|
||||
if (compute_password_element(data->grp, data->group_num,
|
||||
data->password, data->password_len,
|
||||
data->id_server, data->id_server_len,
|
||||
data->id_peer, data->id_peer_len,
|
||||
id->token)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): computed %d bit PWE...",
|
||||
BN_num_bits(data->grp->prime));
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
1 + sizeof(struct eap_pwd_id) + data->id_peer_len,
|
||||
EAP_CODE_RESPONSE, eap_get_id(reqData));
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(resp, EAP_PWD_OPCODE_ID_EXCH);
|
||||
wpabuf_put_be16(resp, data->group_num);
|
||||
wpabuf_put_u8(resp, EAP_PWD_DEFAULT_RAND_FUNC);
|
||||
wpabuf_put_u8(resp, EAP_PWD_DEFAULT_PRF);
|
||||
wpabuf_put_data(resp, id->token, sizeof(id->token));
|
||||
wpabuf_put_u8(resp, EAP_PWD_PREP_NONE);
|
||||
wpabuf_put_data(resp, data->id_peer, data->id_peer_len);
|
||||
|
||||
eap_pwd_state(data, PWD_Commit_Req);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
struct wpabuf *resp = NULL;
|
||||
EC_POINT *K = NULL, *point = NULL;
|
||||
BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL;
|
||||
u16 offset;
|
||||
u8 *ptr, *scalar = NULL, *element = NULL;
|
||||
|
||||
if (((data->private_value = BN_new()) == NULL) ||
|
||||
((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((cofactor = BN_new()) == NULL) ||
|
||||
((data->my_scalar = BN_new()) == NULL) ||
|
||||
((mask = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor "
|
||||
"for curve");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
BN_rand_range(data->private_value, data->grp->order);
|
||||
BN_rand_range(mask, data->grp->order);
|
||||
BN_add(data->my_scalar, data->private_value, mask);
|
||||
BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
|
||||
data->bnctx);
|
||||
|
||||
if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
|
||||
data->grp->pwe, mask, data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation "
|
||||
"fail");
|
||||
eap_pwd_state(data, FAILURE);
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
|
||||
{
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
|
||||
goto fin;
|
||||
}
|
||||
BN_free(mask);
|
||||
|
||||
if (((x = BN_new()) == NULL) ||
|
||||
((y = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* process the request */
|
||||
if (((data->server_scalar = BN_new()) == NULL) ||
|
||||
((data->k = BN_new()) == NULL) ||
|
||||
((K = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((point = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((data->server_element = EC_POINT_new(data->grp->group)) == NULL))
|
||||
{
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* element, x then y, followed by scalar */
|
||||
ptr = (u8 *) payload;
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
|
||||
ptr += BN_num_bytes(data->grp->prime);
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
|
||||
ptr += BN_num_bytes(data->grp->prime);
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar);
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
|
||||
data->server_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* check to ensure server's element is not in a small sub-group */
|
||||
if (BN_cmp(cofactor, BN_value_one())) {
|
||||
if (!EC_POINT_mul(data->grp->group, point, NULL,
|
||||
data->server_element, cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
|
||||
"server element by order!\n");
|
||||
goto fin;
|
||||
}
|
||||
if (EC_POINT_is_at_infinity(data->grp->group, point)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): server element "
|
||||
"is at infinity!\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute the shared key, k */
|
||||
if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
|
||||
data->server_scalar, data->bnctx)) ||
|
||||
(!EC_POINT_add(data->grp->group, K, K, data->server_element,
|
||||
data->bnctx)) ||
|
||||
(!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
|
||||
data->bnctx))) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* ensure that the shared key isn't in a small sub-group */
|
||||
if (BN_cmp(cofactor, BN_value_one())) {
|
||||
if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
|
||||
NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply "
|
||||
"shared key point by order");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This check is strictly speaking just for the case above where
|
||||
* co-factor > 1 but it was suggested that even though this is probably
|
||||
* never going to happen it is a simple and safe check "just to be
|
||||
* sure" so let's be safe.
|
||||
*/
|
||||
if (EC_POINT_is_at_infinity(data->grp->group, K)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at "
|
||||
"infinity!\n");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
|
||||
NULL, data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract "
|
||||
"shared secret from point");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* now do the response */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
|
||||
((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
|
||||
NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/*
|
||||
* bignums occupy as little memory as possible so one that is
|
||||
* sufficiently smaller than the prime or order might need pre-pending
|
||||
* with zeros.
|
||||
*/
|
||||
os_memset(scalar, 0, BN_num_bytes(data->grp->order));
|
||||
os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
|
||||
offset = BN_num_bytes(data->grp->order) -
|
||||
BN_num_bytes(data->my_scalar);
|
||||
BN_bn2bin(data->my_scalar, scalar + offset);
|
||||
|
||||
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
|
||||
BN_bn2bin(x, element + offset);
|
||||
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
|
||||
BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
sizeof(struct eap_pwd_hdr) +
|
||||
BN_num_bytes(data->grp->order) +
|
||||
(2 * BN_num_bytes(data->grp->prime)),
|
||||
EAP_CODE_RESPONSE, eap_get_id(reqData));
|
||||
if (resp == NULL)
|
||||
goto fin;
|
||||
|
||||
wpabuf_put_u8(resp, EAP_PWD_OPCODE_COMMIT_EXCH);
|
||||
|
||||
/* we send the element as (x,y) follwed by the scalar */
|
||||
wpabuf_put_data(resp, element, (2 * BN_num_bytes(data->grp->prime)));
|
||||
wpabuf_put_data(resp, scalar, BN_num_bytes(data->grp->order));
|
||||
|
||||
fin:
|
||||
os_free(scalar);
|
||||
os_free(element);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
BN_free(cofactor);
|
||||
EC_POINT_free(K);
|
||||
EC_POINT_free(point);
|
||||
if (resp == NULL)
|
||||
eap_pwd_state(data, FAILURE);
|
||||
else
|
||||
eap_pwd_state(data, PWD_Confirm_Req);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
struct wpabuf *resp = NULL;
|
||||
BIGNUM *x = NULL, *y = NULL;
|
||||
HMAC_CTX ctx;
|
||||
u32 cs;
|
||||
u16 grp;
|
||||
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
|
||||
|
||||
/*
|
||||
* first build up the ciphersuite which is group | random_function |
|
||||
* prf
|
||||
*/
|
||||
grp = htons(data->group_num);
|
||||
ptr = (u8 *) &cs;
|
||||
os_memcpy(ptr, &grp, sizeof(u16));
|
||||
ptr += sizeof(u16);
|
||||
*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
|
||||
ptr += sizeof(u8);
|
||||
*ptr = EAP_PWD_DEFAULT_PRF;
|
||||
|
||||
/* each component of the cruft will be at most as big as the prime */
|
||||
if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
|
||||
((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/*
|
||||
* server's commit is H(k | server_element | server_scalar |
|
||||
* peer_element | peer_scalar | ciphersuite)
|
||||
*/
|
||||
H_Init(&ctx);
|
||||
|
||||
/*
|
||||
* zero the memory each time because this is mod prime math and some
|
||||
* value may start with a few zeros and the previous one did not.
|
||||
*/
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->k, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->server_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->server_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* my element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* my scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->my_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* the ciphersuite */
|
||||
H_Update(&ctx, (u8 *) &cs, sizeof(u32));
|
||||
|
||||
/* random function fin */
|
||||
H_Final(&ctx, conf);
|
||||
|
||||
ptr = (u8 *) payload;
|
||||
if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified");
|
||||
|
||||
/*
|
||||
* compute confirm:
|
||||
* H(k | peer_element | peer_scalar | server_element | server_scalar |
|
||||
* ciphersuite)
|
||||
*/
|
||||
H_Init(&ctx);
|
||||
|
||||
/* k */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->k, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* my element */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* my scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->my_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* server element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->server_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->server_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* the ciphersuite */
|
||||
H_Update(&ctx, (u8 *) &cs, sizeof(u32));
|
||||
|
||||
/* all done */
|
||||
H_Final(&ctx, conf);
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
|
||||
EAP_CODE_RESPONSE, eap_get_id(reqData));
|
||||
if (resp == NULL)
|
||||
goto fin;
|
||||
|
||||
wpabuf_put_u8(resp, EAP_PWD_OPCODE_CONFIRM_EXCH);
|
||||
wpabuf_put_data(resp, conf, SHA256_DIGEST_LENGTH);
|
||||
|
||||
if (compute_keys(data->grp, data->bnctx, data->k,
|
||||
data->my_scalar, data->server_scalar, conf, ptr,
|
||||
&cs, data->msk, data->emsk) < 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | "
|
||||
"EMSK");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
fin:
|
||||
os_free(cruft);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
ret->methodState = METHOD_DONE;
|
||||
if (resp == NULL) {
|
||||
ret->decision = DECISION_FAIL;
|
||||
eap_pwd_state(data, FAILURE);
|
||||
} else {
|
||||
ret->decision = DECISION_UNCOND_SUCC;
|
||||
eap_pwd_state(data, SUCCESS);
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
struct wpabuf *resp = NULL;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
u8 exch;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len);
|
||||
if ((pos == NULL) || (len < 1)) {
|
||||
ret->ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Received frame: opcode %d", *pos);
|
||||
|
||||
ret->ignore = FALSE;
|
||||
ret->methodState = METHOD_MAY_CONT;
|
||||
ret->decision = DECISION_FAIL;
|
||||
ret->allowNotifications = FALSE;
|
||||
|
||||
exch = *pos & 0x3f;
|
||||
switch (exch) {
|
||||
case EAP_PWD_OPCODE_ID_EXCH:
|
||||
resp = eap_pwd_perform_id_exchange(sm, data, ret, reqData,
|
||||
pos + 1, len - 1);
|
||||
break;
|
||||
case EAP_PWD_OPCODE_COMMIT_EXCH:
|
||||
resp = eap_pwd_perform_commit_exchange(sm, data, ret, reqData,
|
||||
pos + 1, len - 1);
|
||||
break;
|
||||
case EAP_PWD_OPCODE_CONFIRM_EXCH:
|
||||
resp = eap_pwd_perform_confirm_exchange(sm, data, ret, reqData,
|
||||
pos + 1, len - 1);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown "
|
||||
"opcode %d", exch);
|
||||
break;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
if ((key = os_malloc(EAP_EMSK_LEN)) == NULL)
|
||||
return NULL;
|
||||
|
||||
os_memcpy(key, data->emsk, EAP_EMSK_LEN);
|
||||
*len = EAP_EMSK_LEN;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
int eap_peer_pwd_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
EVP_add_digest(EVP_sha256());
|
||||
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_pwd_init;
|
||||
eap->deinit = eap_pwd_deinit;
|
||||
eap->process = eap_pwd_process;
|
||||
eap->isKeyAvailable = eap_pwd_key_available;
|
||||
eap->getKey = eap_pwd_getkey;
|
||||
eap->get_emsk = eap_pwd_get_emsk;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
eap_peer_method_free(eap);
|
||||
return ret;
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* EAP peer method: EAP-TLS (RFC 2716)
|
||||
* 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 "crypto/tls.h"
|
||||
#include "eap_i.h"
|
||||
#include "eap_tls_common.h"
|
||||
#include "eap_config.h"
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv);
|
||||
|
||||
|
||||
struct eap_tls_data {
|
||||
struct eap_ssl_data ssl;
|
||||
u8 *key_data;
|
||||
};
|
||||
|
||||
|
||||
static void * eap_tls_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_tls_data *data;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL ||
|
||||
((sm->init_phase2 ? config->private_key2 : config->private_key)
|
||||
== NULL &&
|
||||
(sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
|
||||
eap_tls_deinit(sm, data);
|
||||
if (config->engine) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
|
||||
"PIN");
|
||||
eap_sm_request_pin(sm);
|
||||
sm->ignore = TRUE;
|
||||
} else if (config->private_key && !config->private_key_passwd)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
|
||||
"key passphrase");
|
||||
eap_sm_request_passphrase(sm);
|
||||
sm->ignore = TRUE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data == NULL)
|
||||
return;
|
||||
eap_peer_tls_ssl_deinit(sm, &data->ssl);
|
||||
os_free(data->key_data);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
|
||||
struct eap_tls_data *data,
|
||||
struct eap_method_ret *ret, int res,
|
||||
struct wpabuf *resp, u8 id)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
|
||||
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_FAIL;
|
||||
|
||||
if (res == -1) {
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config) {
|
||||
/*
|
||||
* The TLS handshake failed. So better forget the old
|
||||
* PIN. It may be wrong, we cannot be sure but trying
|
||||
* the wrong one again might block it on the card--so
|
||||
* better ask the user again.
|
||||
*/
|
||||
os_free(config->pin);
|
||||
config->pin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (resp) {
|
||||
/*
|
||||
* This is likely an alert message, so send it instead of just
|
||||
* ACKing the error.
|
||||
*/
|
||||
return resp;
|
||||
}
|
||||
|
||||
return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
|
||||
struct eap_method_ret *ret)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
|
||||
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_UNCOND_SUCC;
|
||||
|
||||
os_free(data->key_data);
|
||||
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
|
||||
"client EAP encryption",
|
||||
EAP_TLS_KEY_LEN +
|
||||
EAP_EMSK_LEN);
|
||||
if (data->key_data) {
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
|
||||
data->key_data, EAP_TLS_KEY_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
|
||||
data->key_data + EAP_TLS_KEY_LEN,
|
||||
EAP_EMSK_LEN);
|
||||
} else {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
size_t left;
|
||||
int res;
|
||||
struct wpabuf *resp;
|
||||
u8 flags, id;
|
||||
const u8 *pos;
|
||||
struct eap_tls_data *data = priv;
|
||||
|
||||
pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
|
||||
reqData, &left, &flags);
|
||||
if (pos == NULL)
|
||||
return NULL;
|
||||
id = eap_get_id(reqData);
|
||||
|
||||
if (flags & EAP_TLS_FLAGS_START) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
|
||||
left = 0; /* make sure that this frame is empty, even though it
|
||||
* should always be, anyway */
|
||||
}
|
||||
|
||||
resp = NULL;
|
||||
res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
|
||||
pos, left, &resp);
|
||||
|
||||
if (res < 0) {
|
||||
return eap_tls_failure(sm, data, ret, res, resp, id);
|
||||
}
|
||||
|
||||
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
|
||||
eap_tls_success(sm, data, ret);
|
||||
|
||||
if (res == 1) {
|
||||
wpabuf_free(resp);
|
||||
return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
os_free(data->key_data);
|
||||
data->key_data = NULL;
|
||||
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
return priv;
|
||||
}
|
||||
|
||||
|
||||
static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
|
||||
size_t buflen, int verbose)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
return data->key_data != NULL;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->key_data == NULL)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_TLS_KEY_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = EAP_TLS_KEY_LEN;
|
||||
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->key_data == NULL)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_EMSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = EAP_EMSK_LEN;
|
||||
os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
int eap_peer_tls_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_tls_init;
|
||||
eap->deinit = eap_tls_deinit;
|
||||
eap->process = eap_tls_process;
|
||||
eap->isKeyAvailable = eap_tls_isKeyAvailable;
|
||||
eap->getKey = eap_tls_getKey;
|
||||
eap->get_status = eap_tls_get_status;
|
||||
eap->has_reauth_data = eap_tls_has_reauth_data;
|
||||
eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
|
||||
eap->init_for_reauth = eap_tls_init_for_reauth;
|
||||
eap->get_emsk = eap_tls_get_emsk;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
eap_peer_method_free(eap);
|
||||
return ret;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
|
@ -1,844 +0,0 @@
|
|||
/*
|
||||
* hostapd / EAP-pwd (RFC 5931) server
|
||||
* Copyright (c) 2010, Dan Harkins <dharkins@lounge.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the BSD license.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_server/eap_i.h"
|
||||
#include "eap_common/eap_pwd_common.h"
|
||||
|
||||
|
||||
struct eap_pwd_data {
|
||||
enum {
|
||||
PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE
|
||||
} state;
|
||||
u8 *id_peer;
|
||||
size_t id_peer_len;
|
||||
u8 *id_server;
|
||||
size_t id_server_len;
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
u32 token;
|
||||
u16 group_num;
|
||||
EAP_PWD_group *grp;
|
||||
|
||||
BIGNUM *k;
|
||||
BIGNUM *private_value;
|
||||
BIGNUM *peer_scalar;
|
||||
BIGNUM *my_scalar;
|
||||
EC_POINT *my_element;
|
||||
EC_POINT *peer_element;
|
||||
|
||||
u8 my_confirm[SHA256_DIGEST_LENGTH];
|
||||
|
||||
u8 msk[EAP_MSK_LEN];
|
||||
u8 emsk[EAP_EMSK_LEN];
|
||||
|
||||
BN_CTX *bnctx;
|
||||
};
|
||||
|
||||
|
||||
static const char * eap_pwd_state_txt(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case PWD_ID_Req:
|
||||
return "PWD-ID-Req";
|
||||
case PWD_Commit_Req:
|
||||
return "PWD-Commit-Req";
|
||||
case PWD_Confirm_Req:
|
||||
return "PWD-Confirm-Req";
|
||||
case SUCCESS:
|
||||
return "SUCCESS";
|
||||
case FAILURE:
|
||||
return "FAILURE";
|
||||
default:
|
||||
return "PWD-Unk";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void eap_pwd_state(struct eap_pwd_data *data, int state)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s",
|
||||
eap_pwd_state_txt(data->state), eap_pwd_state_txt(state));
|
||||
data->state = state;
|
||||
}
|
||||
|
||||
|
||||
static void * eap_pwd_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_pwd_data *data;
|
||||
|
||||
if (sm->user == NULL || sm->user->password == NULL ||
|
||||
sm->user->password_len == 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not "
|
||||
"configured");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->group_num = sm->pwd_group;
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d",
|
||||
data->group_num);
|
||||
data->state = PWD_ID_Req;
|
||||
|
||||
data->id_server = (u8 *) os_strdup("server");
|
||||
if (data->id_server)
|
||||
data->id_server_len = os_strlen((char *) data->id_server);
|
||||
|
||||
data->password = os_malloc(sm->user->password_len);
|
||||
if (data->password == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
|
||||
"fail");
|
||||
os_free(data->id_server);
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
data->password_len = sm->user->password_len;
|
||||
os_memcpy(data->password, sm->user->password, data->password_len);
|
||||
|
||||
data->bnctx = BN_CTX_new();
|
||||
if (data->bnctx == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
|
||||
os_free(data->password);
|
||||
os_free(data->id_server);
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pwd_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
|
||||
BN_free(data->private_value);
|
||||
BN_free(data->peer_scalar);
|
||||
BN_free(data->my_scalar);
|
||||
BN_free(data->k);
|
||||
BN_CTX_free(data->bnctx);
|
||||
EC_POINT_free(data->my_element);
|
||||
EC_POINT_free(data->peer_element);
|
||||
os_free(data->id_peer);
|
||||
os_free(data->id_server);
|
||||
os_free(data->password);
|
||||
if (data->grp) {
|
||||
EC_GROUP_free(data->grp->group);
|
||||
EC_POINT_free(data->grp->pwe);
|
||||
BN_free(data->grp->order);
|
||||
BN_free(data->grp->prime);
|
||||
os_free(data->grp);
|
||||
}
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
|
||||
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
sizeof(struct eap_pwd_hdr) +
|
||||
sizeof(struct eap_pwd_id) + data->id_server_len,
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL) {
|
||||
eap_pwd_state(data, FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* an lfsr is good enough to generate unpredictable tokens */
|
||||
data->token = os_random();
|
||||
wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH);
|
||||
wpabuf_put_be16(req, data->group_num);
|
||||
wpabuf_put_u8(req, EAP_PWD_DEFAULT_RAND_FUNC);
|
||||
wpabuf_put_u8(req, EAP_PWD_DEFAULT_PRF);
|
||||
wpabuf_put_data(req, &data->token, sizeof(data->token));
|
||||
wpabuf_put_u8(req, EAP_PWD_PREP_NONE);
|
||||
wpabuf_put_data(req, data->id_server, data->id_server_len);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req = NULL;
|
||||
BIGNUM *mask = NULL, *x = NULL, *y = NULL;
|
||||
u8 *scalar = NULL, *element = NULL;
|
||||
u16 offset;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request");
|
||||
|
||||
if (((data->private_value = BN_new()) == NULL) ||
|
||||
((data->my_element = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((data->my_scalar = BN_new()) == NULL) ||
|
||||
((mask = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
BN_rand_range(data->private_value, data->grp->order);
|
||||
BN_rand_range(mask, data->grp->order);
|
||||
BN_add(data->my_scalar, data->private_value, mask);
|
||||
BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
|
||||
data->bnctx);
|
||||
|
||||
if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
|
||||
data->grp->pwe, mask, data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation "
|
||||
"fail");
|
||||
eap_pwd_state(data, FAILURE);
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx))
|
||||
{
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
BN_free(mask);
|
||||
|
||||
if (((x = BN_new()) == NULL) ||
|
||||
((y = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) ||
|
||||
((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) ==
|
||||
NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/*
|
||||
* bignums occupy as little memory as possible so one that is
|
||||
* sufficiently smaller than the prime or order might need pre-pending
|
||||
* with zeros.
|
||||
*/
|
||||
os_memset(scalar, 0, BN_num_bytes(data->grp->order));
|
||||
os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2);
|
||||
offset = BN_num_bytes(data->grp->order) -
|
||||
BN_num_bytes(data->my_scalar);
|
||||
BN_bn2bin(data->my_scalar, scalar + offset);
|
||||
|
||||
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
|
||||
BN_bn2bin(x, element + offset);
|
||||
offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
|
||||
BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
|
||||
|
||||
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
sizeof(struct eap_pwd_hdr) +
|
||||
(2 * BN_num_bytes(data->grp->prime)) +
|
||||
BN_num_bytes(data->grp->order),
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL)
|
||||
goto fin;
|
||||
wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH);
|
||||
|
||||
/* We send the element as (x,y) followed by the scalar */
|
||||
wpabuf_put_data(req, element, (2 * BN_num_bytes(data->grp->prime)));
|
||||
wpabuf_put_data(req, scalar, BN_num_bytes(data->grp->order));
|
||||
|
||||
fin:
|
||||
os_free(scalar);
|
||||
os_free(element);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
if (req == NULL)
|
||||
eap_pwd_state(data, FAILURE);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req = NULL;
|
||||
BIGNUM *x = NULL, *y = NULL;
|
||||
HMAC_CTX ctx;
|
||||
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
|
||||
u16 grp;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
|
||||
|
||||
/* Each component of the cruft will be at most as big as the prime */
|
||||
if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
|
||||
((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/*
|
||||
* commit is H(k | server_element | server_scalar | peer_element |
|
||||
* peer_scalar | ciphersuite)
|
||||
*/
|
||||
H_Init(&ctx);
|
||||
|
||||
/*
|
||||
* Zero the memory each time because this is mod prime math and some
|
||||
* value may start with a few zeros and the previous one did not.
|
||||
*
|
||||
* First is k
|
||||
*/
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->k, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->my_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* peer element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->peer_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* peer scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->peer_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* ciphersuite */
|
||||
grp = htons(data->group_num);
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
ptr = cruft;
|
||||
os_memcpy(ptr, &grp, sizeof(u16));
|
||||
ptr += sizeof(u16);
|
||||
*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
|
||||
ptr += sizeof(u8);
|
||||
*ptr = EAP_PWD_DEFAULT_PRF;
|
||||
ptr += sizeof(u8);
|
||||
H_Update(&ctx, cruft, ptr-cruft);
|
||||
|
||||
/* all done with the random function */
|
||||
H_Final(&ctx, conf);
|
||||
os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
|
||||
|
||||
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
|
||||
EAP_CODE_REQUEST, id);
|
||||
if (req == NULL)
|
||||
goto fin;
|
||||
|
||||
wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH);
|
||||
wpabuf_put_data(req, conf, SHA256_DIGEST_LENGTH);
|
||||
|
||||
fin:
|
||||
os_free(cruft);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
if (req == NULL)
|
||||
eap_pwd_state(data, FAILURE);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
|
||||
switch (data->state) {
|
||||
case PWD_ID_Req:
|
||||
return eap_pwd_build_id_req(sm, data, id);
|
||||
case PWD_Commit_Req:
|
||||
return eap_pwd_build_commit_req(sm, data, id);
|
||||
case PWD_Confirm_Req:
|
||||
return eap_pwd_build_confirm_req(sm, data, id);
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req",
|
||||
data->state);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pwd_check(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
|
||||
if (pos == NULL || len < 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: opcode=%d", *pos);
|
||||
|
||||
if (data->state == PWD_ID_Req && *pos == EAP_PWD_OPCODE_ID_EXCH)
|
||||
return FALSE;
|
||||
|
||||
if (data->state == PWD_Commit_Req &&
|
||||
*pos == EAP_PWD_OPCODE_COMMIT_EXCH)
|
||||
return FALSE;
|
||||
|
||||
if (data->state == PWD_Confirm_Req &&
|
||||
*pos == EAP_PWD_OPCODE_CONFIRM_EXCH)
|
||||
return FALSE;
|
||||
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d",
|
||||
*pos, data->state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void eap_pwd_process_id_resp(struct eap_sm *sm,
|
||||
struct eap_pwd_data *data,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
struct eap_pwd_id *id;
|
||||
|
||||
if (payload_len < sizeof(struct eap_pwd_id)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response");
|
||||
return;
|
||||
}
|
||||
|
||||
id = (struct eap_pwd_id *) payload;
|
||||
if ((data->group_num != be_to_host16(id->group_num)) ||
|
||||
(id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
|
||||
(os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
|
||||
(id->prf != EAP_PWD_DEFAULT_PRF)) {
|
||||
wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
|
||||
eap_pwd_state(data, FAILURE);
|
||||
return;
|
||||
}
|
||||
data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id));
|
||||
if (data->id_peer == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail");
|
||||
return;
|
||||
}
|
||||
data->id_peer_len = payload_len - sizeof(struct eap_pwd_id);
|
||||
os_memcpy(data->id_peer, id->identity, data->id_peer_len);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of",
|
||||
data->id_peer, data->id_peer_len);
|
||||
|
||||
if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for "
|
||||
"group");
|
||||
return;
|
||||
}
|
||||
if (compute_password_element(data->grp, data->group_num,
|
||||
data->password, data->password_len,
|
||||
data->id_server, data->id_server_len,
|
||||
data->id_peer, data->id_peer_len,
|
||||
(u8 *) &data->token)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute "
|
||||
"PWE");
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...",
|
||||
BN_num_bits(data->grp->prime));
|
||||
|
||||
eap_pwd_state(data, PWD_Commit_Req);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
u8 *ptr;
|
||||
BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
|
||||
EC_POINT *K = NULL, *point = NULL;
|
||||
int res = 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response");
|
||||
|
||||
if (((data->peer_scalar = BN_new()) == NULL) ||
|
||||
((data->k = BN_new()) == NULL) ||
|
||||
((cofactor = BN_new()) == NULL) ||
|
||||
((x = BN_new()) == NULL) ||
|
||||
((y = BN_new()) == NULL) ||
|
||||
((point = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((K = EC_POINT_new(data->grp->group)) == NULL) ||
|
||||
((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get "
|
||||
"cofactor for curve");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* element, x then y, followed by scalar */
|
||||
ptr = (u8 *) payload;
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x);
|
||||
ptr += BN_num_bytes(data->grp->prime);
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y);
|
||||
ptr += BN_num_bytes(data->grp->prime);
|
||||
BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar);
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group,
|
||||
data->peer_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* check to ensure peer's element is not in a small sub-group */
|
||||
if (BN_cmp(cofactor, BN_value_one())) {
|
||||
if (!EC_POINT_mul(data->grp->group, point, NULL,
|
||||
data->peer_element, cofactor, NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
|
||||
"multiply peer element by order");
|
||||
goto fin;
|
||||
}
|
||||
if (EC_POINT_is_at_infinity(data->grp->group, point)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): peer element "
|
||||
"is at infinity!\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute the shared key, k */
|
||||
if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe,
|
||||
data->peer_scalar, data->bnctx)) ||
|
||||
(!EC_POINT_add(data->grp->group, K, K, data->peer_element,
|
||||
data->bnctx)) ||
|
||||
(!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value,
|
||||
data->bnctx))) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key "
|
||||
"fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/* ensure that the shared key isn't in a small sub-group */
|
||||
if (BN_cmp(cofactor, BN_value_one())) {
|
||||
if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor,
|
||||
NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): cannot "
|
||||
"multiply shared key point by order!\n");
|
||||
goto fin;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This check is strictly speaking just for the case above where
|
||||
* co-factor > 1 but it was suggested that even though this is probably
|
||||
* never going to happen it is a simple and safe check "just to be
|
||||
* sure" so let's be safe.
|
||||
*/
|
||||
if (EC_POINT_is_at_infinity(data->grp->group, K)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is "
|
||||
"at infinity");
|
||||
goto fin;
|
||||
}
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k,
|
||||
NULL, data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract "
|
||||
"shared secret from secret point");
|
||||
goto fin;
|
||||
}
|
||||
res = 1;
|
||||
|
||||
fin:
|
||||
EC_POINT_free(K);
|
||||
EC_POINT_free(point);
|
||||
BN_free(cofactor);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
|
||||
if (res)
|
||||
eap_pwd_state(data, PWD_Confirm_Req);
|
||||
else
|
||||
eap_pwd_state(data, FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data,
|
||||
const u8 *payload, size_t payload_len)
|
||||
{
|
||||
BIGNUM *x = NULL, *y = NULL;
|
||||
HMAC_CTX ctx;
|
||||
u32 cs;
|
||||
u16 grp;
|
||||
u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
|
||||
|
||||
/* build up the ciphersuite: group | random_function | prf */
|
||||
grp = htons(data->group_num);
|
||||
ptr = (u8 *) &cs;
|
||||
os_memcpy(ptr, &grp, sizeof(u16));
|
||||
ptr += sizeof(u16);
|
||||
*ptr = EAP_PWD_DEFAULT_RAND_FUNC;
|
||||
ptr += sizeof(u8);
|
||||
*ptr = EAP_PWD_DEFAULT_PRF;
|
||||
|
||||
/* each component of the cruft will be at most as big as the prime */
|
||||
if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) ||
|
||||
((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
/*
|
||||
* commit is H(k | peer_element | peer_scalar | server_element |
|
||||
* server_scalar | ciphersuite)
|
||||
*/
|
||||
H_Init(&ctx);
|
||||
|
||||
/* k */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->k, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* peer element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->peer_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* peer scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->peer_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* server element: x, y */
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
|
||||
data->my_element, x, y,
|
||||
data->bnctx)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point "
|
||||
"assignment fail");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(x, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(y, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
|
||||
|
||||
/* server scalar */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
BN_bn2bin(data->my_scalar, cruft);
|
||||
H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
|
||||
|
||||
/* ciphersuite */
|
||||
os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
|
||||
H_Update(&ctx, (u8 *)&cs, sizeof(u32));
|
||||
|
||||
/* all done */
|
||||
H_Final(&ctx, conf);
|
||||
|
||||
ptr = (u8 *) payload;
|
||||
if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
|
||||
wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
|
||||
"verify");
|
||||
goto fin;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified");
|
||||
if (compute_keys(data->grp, data->bnctx, data->k,
|
||||
data->peer_scalar, data->my_scalar, conf,
|
||||
data->my_confirm, &cs, data->msk, data->emsk) < 0)
|
||||
eap_pwd_state(data, FAILURE);
|
||||
else
|
||||
eap_pwd_state(data, SUCCESS);
|
||||
|
||||
fin:
|
||||
os_free(cruft);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
}
|
||||
|
||||
|
||||
static void eap_pwd_process(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
u8 exch;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len);
|
||||
if ((pos == NULL) || (len < 1)) {
|
||||
wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d",
|
||||
(pos == NULL) ? "is NULL" : "is not NULL",
|
||||
(int) len);
|
||||
return;
|
||||
}
|
||||
|
||||
exch = *pos & 0x3f;
|
||||
switch (exch) {
|
||||
case EAP_PWD_OPCODE_ID_EXCH:
|
||||
eap_pwd_process_id_resp(sm, data, pos + 1, len - 1);
|
||||
break;
|
||||
case EAP_PWD_OPCODE_COMMIT_EXCH:
|
||||
eap_pwd_process_commit_resp(sm, data, pos + 1, len - 1);
|
||||
break;
|
||||
case EAP_PWD_OPCODE_CONFIRM_EXCH:
|
||||
eap_pwd_process_confirm_resp(sm, data, pos + 1, len - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_MSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
os_memcpy(key, data->msk, EAP_MSK_LEN);
|
||||
*len = EAP_MSK_LEN;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_EMSK_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
os_memcpy(key, data->emsk, EAP_EMSK_LEN);
|
||||
*len = EAP_EMSK_LEN;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_pwd_data *data = priv;
|
||||
return (data->state == SUCCESS) || (data->state == FAILURE);
|
||||
}
|
||||
|
||||
|
||||
int eap_server_pwd_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
struct timeval tp;
|
||||
struct timezone tz;
|
||||
u32 sr;
|
||||
|
||||
EVP_add_digest(EVP_sha256());
|
||||
|
||||
sr = 0xdeaddada;
|
||||
(void) gettimeofday(&tp, &tz);
|
||||
sr ^= (tp.tv_sec ^ tp.tv_usec);
|
||||
srandom(sr);
|
||||
|
||||
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_PWD,
|
||||
"PWD");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_pwd_init;
|
||||
eap->reset = eap_pwd_reset;
|
||||
eap->buildReq = eap_pwd_build_req;
|
||||
eap->check = eap_pwd_check;
|
||||
eap->process = eap_pwd_process;
|
||||
eap->isDone = eap_pwd_is_done;
|
||||
eap->getKey = eap_pwd_getkey;
|
||||
eap->get_emsk = eap_pwd_get_emsk;
|
||||
eap->isSuccess = eap_pwd_is_success;
|
||||
|
||||
ret = eap_server_method_register(eap);
|
||||
if (ret)
|
||||
eap_server_method_free(eap);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
/*
|
||||
* hostapd / EAP-TLS (RFC 2716)
|
||||
* 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 "eap_i.h"
|
||||
#include "eap_tls_common.h"
|
||||
#include "crypto/tls.h"
|
||||
|
||||
|
||||
static void eap_tls_reset(struct eap_sm *sm, void *priv);
|
||||
|
||||
|
||||
struct eap_tls_data {
|
||||
struct eap_ssl_data ssl;
|
||||
enum { START, CONTINUE, SUCCESS, FAILURE } state;
|
||||
int established;
|
||||
};
|
||||
|
||||
|
||||
static const char * eap_tls_state_txt(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case START:
|
||||
return "START";
|
||||
case CONTINUE:
|
||||
return "CONTINUE";
|
||||
case SUCCESS:
|
||||
return "SUCCESS";
|
||||
case FAILURE:
|
||||
return "FAILURE";
|
||||
default:
|
||||
return "Unknown?!";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_state(struct eap_tls_data *data, int state)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
|
||||
eap_tls_state_txt(data->state),
|
||||
eap_tls_state_txt(state));
|
||||
data->state = state;
|
||||
}
|
||||
|
||||
|
||||
static void * eap_tls_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_tls_data *data;
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
data->state = START;
|
||||
|
||||
if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
|
||||
eap_tls_reset(sm, data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_reset(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data == NULL)
|
||||
return;
|
||||
eap_server_tls_ssl_deinit(sm, &data->ssl);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
|
||||
struct eap_tls_data *data, u8 id)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
|
||||
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
|
||||
id);
|
||||
if (req == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
|
||||
"request");
|
||||
eap_tls_state(data, FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
|
||||
|
||||
eap_tls_state(data, CONTINUE);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
struct wpabuf *res;
|
||||
|
||||
if (data->ssl.state == FRAG_ACK) {
|
||||
return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
|
||||
}
|
||||
|
||||
if (data->ssl.state == WAIT_FRAG_ACK) {
|
||||
res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
|
||||
id);
|
||||
goto check_established;
|
||||
}
|
||||
|
||||
switch (data->state) {
|
||||
case START:
|
||||
return eap_tls_build_start(sm, data, id);
|
||||
case CONTINUE:
|
||||
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
|
||||
data->established = 1;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
|
||||
__func__, data->state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
|
||||
|
||||
check_established:
|
||||
if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
|
||||
/* TLS handshake has been completed and there are no more
|
||||
* fragments waiting to be sent out. */
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
|
||||
eap_tls_state(data, SUCCESS);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
|
||||
if (pos == NULL || len < 1) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
|
||||
const struct wpabuf *respData)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
|
||||
"handshake message");
|
||||
return;
|
||||
}
|
||||
if (eap_server_tls_phase1(sm, &data->ssl) < 0)
|
||||
eap_tls_state(data, FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_process(struct eap_sm *sm, void *priv,
|
||||
struct wpabuf *respData)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (eap_server_tls_process(sm, &data->ssl, respData, data,
|
||||
EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
|
||||
0)
|
||||
eap_tls_state(data, FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
return data->state == SUCCESS || data->state == FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
u8 *eapKeyData;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
|
||||
"client EAP encryption",
|
||||
EAP_TLS_KEY_LEN);
|
||||
if (eapKeyData) {
|
||||
*len = EAP_TLS_KEY_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
|
||||
eapKeyData, EAP_TLS_KEY_LEN);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
|
||||
}
|
||||
|
||||
return eapKeyData;
|
||||
}
|
||||
|
||||
|
||||
static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
u8 *eapKeyData, *emsk;
|
||||
|
||||
if (data->state != SUCCESS)
|
||||
return NULL;
|
||||
|
||||
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
|
||||
"client EAP encryption",
|
||||
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
|
||||
if (eapKeyData) {
|
||||
emsk = os_malloc(EAP_EMSK_LEN);
|
||||
if (emsk)
|
||||
os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
|
||||
EAP_EMSK_LEN);
|
||||
os_free(eapKeyData);
|
||||
} else
|
||||
emsk = NULL;
|
||||
|
||||
if (emsk) {
|
||||
*len = EAP_EMSK_LEN;
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
|
||||
emsk, EAP_EMSK_LEN);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
|
||||
}
|
||||
|
||||
return emsk;
|
||||
}
|
||||
|
||||
|
||||
static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
return data->state == SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int eap_server_tls_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
|
||||
EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_tls_init;
|
||||
eap->reset = eap_tls_reset;
|
||||
eap->buildReq = eap_tls_buildReq;
|
||||
eap->check = eap_tls_check;
|
||||
eap->process = eap_tls_process;
|
||||
eap->isDone = eap_tls_isDone;
|
||||
eap->getKey = eap_tls_getKey;
|
||||
eap->isSuccess = eap_tls_isSuccess;
|
||||
eap->get_emsk = eap_tls_get_emsk;
|
||||
|
||||
ret = eap_server_method_register(eap);
|
||||
if (ret)
|
||||
eap_server_method_free(eap);
|
||||
return ret;
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* hostapd / EAP-SIM database/authenticator gateway
|
||||
* Copyright (c) 2005-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 EAP_SIM_DB_H
|
||||
#define EAP_SIM_DB_H
|
||||
|
||||
#include "eap_common/eap_sim_common.h"
|
||||
|
||||
/* Identity prefixes */
|
||||
#define EAP_SIM_PERMANENT_PREFIX '1'
|
||||
#define EAP_SIM_PSEUDONYM_PREFIX '3'
|
||||
#define EAP_SIM_REAUTH_ID_PREFIX '5'
|
||||
#define EAP_AKA_PERMANENT_PREFIX '0'
|
||||
#define EAP_AKA_PSEUDONYM_PREFIX '2'
|
||||
#define EAP_AKA_REAUTH_ID_PREFIX '4'
|
||||
|
||||
void * eap_sim_db_init(const char *config,
|
||||
void (*get_complete_cb)(void *ctx, void *session_ctx),
|
||||
void *ctx);
|
||||
|
||||
void eap_sim_db_deinit(void *priv);
|
||||
|
||||
int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
|
||||
size_t identity_len, int max_chal,
|
||||
u8 *_rand, u8 *kc, u8 *sres,
|
||||
void *cb_session_ctx);
|
||||
|
||||
#define EAP_SIM_DB_FAILURE -1
|
||||
#define EAP_SIM_DB_PENDING -2
|
||||
|
||||
int eap_sim_db_identity_known(void *priv, const u8 *identity,
|
||||
size_t identity_len);
|
||||
|
||||
char * eap_sim_db_get_next_pseudonym(void *priv, int aka);
|
||||
|
||||
char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
|
||||
|
||||
int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
|
||||
size_t identity_len, char *pseudonym);
|
||||
|
||||
int eap_sim_db_add_reauth(void *priv, const u8 *identity,
|
||||
size_t identity_len, char *reauth_id, u16 counter,
|
||||
const u8 *mk);
|
||||
int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
|
||||
size_t identity_len, char *reauth_id,
|
||||
u16 counter, const u8 *k_encr, const u8 *k_aut,
|
||||
const u8 *k_re);
|
||||
|
||||
const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
|
||||
size_t identity_len, size_t *len);
|
||||
|
||||
struct eap_sim_reauth {
|
||||
struct eap_sim_reauth *next;
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
char *reauth_id;
|
||||
u16 counter;
|
||||
int aka_prime;
|
||||
u8 mk[EAP_SIM_MK_LEN];
|
||||
u8 k_encr[EAP_SIM_K_ENCR_LEN];
|
||||
u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
|
||||
u8 k_re[EAP_AKA_PRIME_K_RE_LEN];
|
||||
};
|
||||
|
||||
struct eap_sim_reauth *
|
||||
eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
|
||||
size_t identity_len);
|
||||
|
||||
void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
|
||||
|
||||
int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
|
||||
size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
|
||||
u8 *ck, u8 *res, size_t *res_len,
|
||||
void *cb_session_ctx);
|
||||
|
||||
int eap_sim_db_resynchronize(void *priv, const u8 *identity,
|
||||
size_t identity_len, const u8 *auts,
|
||||
const u8 *_rand);
|
||||
|
||||
#endif /* EAP_SIM_DB_H */
|
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* IEEE 802.1X-2004 Authenticator - State dump
|
||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "eapol_auth_sm.h"
|
||||
#include "eapol_auth_sm_i.h"
|
||||
|
||||
static inline const char * port_type_txt(PortTypes pt)
|
||||
{
|
||||
switch (pt) {
|
||||
case ForceUnauthorized: return "ForceUnauthorized";
|
||||
case ForceAuthorized: return "ForceAuthorized";
|
||||
case Auto: return "Auto";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * port_state_txt(PortState ps)
|
||||
{
|
||||
switch (ps) {
|
||||
case Unauthorized: return "Unauthorized";
|
||||
case Authorized: return "Authorized";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * ctrl_dir_txt(ControlledDirection dir)
|
||||
{
|
||||
switch (dir) {
|
||||
case Both: return "Both";
|
||||
case In: return "In";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * auth_pae_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case AUTH_PAE_INITIALIZE: return "INITIALIZE";
|
||||
case AUTH_PAE_DISCONNECTED: return "DISCONNECTED";
|
||||
case AUTH_PAE_CONNECTING: return "CONNECTING";
|
||||
case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING";
|
||||
case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED";
|
||||
case AUTH_PAE_ABORTING: return "ABORTING";
|
||||
case AUTH_PAE_HELD: return "HELD";
|
||||
case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH";
|
||||
case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH";
|
||||
case AUTH_PAE_RESTART: return "RESTART";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * be_auth_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case BE_AUTH_REQUEST: return "REQUEST";
|
||||
case BE_AUTH_RESPONSE: return "RESPONSE";
|
||||
case BE_AUTH_SUCCESS: return "SUCCESS";
|
||||
case BE_AUTH_FAIL: return "FAIL";
|
||||
case BE_AUTH_TIMEOUT: return "TIMEOUT";
|
||||
case BE_AUTH_IDLE: return "IDLE";
|
||||
case BE_AUTH_INITIALIZE: return "INITIALIZE";
|
||||
case BE_AUTH_IGNORE: return "IGNORE";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * reauth_timer_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case REAUTH_TIMER_INITIALIZE: return "INITIALIZE";
|
||||
case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * auth_key_tx_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT";
|
||||
case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * key_rx_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE";
|
||||
case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline const char * ctrl_dir_state_txt(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH";
|
||||
case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void eapol_auth_dump_state(FILE *f, const char *prefix,
|
||||
struct eapol_state_machine *sm)
|
||||
{
|
||||
fprintf(f, "%sEAPOL state machine:\n", prefix);
|
||||
fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
|
||||
sm->aWhile, sm->quietWhile, sm->reAuthWhen);
|
||||
#define _SB(b) ((b) ? "TRUE" : "FALSE")
|
||||
fprintf(f,
|
||||
"%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
|
||||
"%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
|
||||
"%s eapSuccess=%s eapTimeout=%s initialize=%s "
|
||||
"keyAvailable=%s\n"
|
||||
"%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
|
||||
"%s portEnabled=%s portValid=%s reAuthenticate=%s\n",
|
||||
prefix, _SB(sm->authAbort), _SB(sm->authFail),
|
||||
port_state_txt(sm->authPortStatus), _SB(sm->authStart),
|
||||
prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
|
||||
_SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
|
||||
prefix, _SB(sm->eap_if->eapSuccess),
|
||||
_SB(sm->eap_if->eapTimeout),
|
||||
_SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
|
||||
prefix, _SB(sm->keyDone), _SB(sm->keyRun),
|
||||
_SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
|
||||
prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
|
||||
_SB(sm->reAuthenticate));
|
||||
|
||||
fprintf(f, "%s Authenticator PAE:\n"
|
||||
"%s state=%s\n"
|
||||
"%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
|
||||
"%s portMode=%s reAuthCount=%d\n"
|
||||
"%s quietPeriod=%d reAuthMax=%d\n"
|
||||
"%s authEntersConnecting=%d\n"
|
||||
"%s authEapLogoffsWhileConnecting=%d\n"
|
||||
"%s authEntersAuthenticating=%d\n"
|
||||
"%s authAuthSuccessesWhileAuthenticating=%d\n"
|
||||
"%s authAuthTimeoutsWhileAuthenticating=%d\n"
|
||||
"%s authAuthFailWhileAuthenticating=%d\n"
|
||||
"%s authAuthEapStartsWhileAuthenticating=%d\n"
|
||||
"%s authAuthEapLogoffWhileAuthenticating=%d\n"
|
||||
"%s authAuthReauthsWhileAuthenticated=%d\n"
|
||||
"%s authAuthEapStartsWhileAuthenticated=%d\n"
|
||||
"%s authAuthEapLogoffWhileAuthenticated=%d\n",
|
||||
prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
|
||||
_SB(sm->eapolLogoff), _SB(sm->eapolStart),
|
||||
_SB(sm->eap_if->eapRestart),
|
||||
prefix, port_type_txt(sm->portMode), sm->reAuthCount,
|
||||
prefix, sm->quietPeriod, sm->reAuthMax,
|
||||
prefix, sm->authEntersConnecting,
|
||||
prefix, sm->authEapLogoffsWhileConnecting,
|
||||
prefix, sm->authEntersAuthenticating,
|
||||
prefix, sm->authAuthSuccessesWhileAuthenticating,
|
||||
prefix, sm->authAuthTimeoutsWhileAuthenticating,
|
||||
prefix, sm->authAuthFailWhileAuthenticating,
|
||||
prefix, sm->authAuthEapStartsWhileAuthenticating,
|
||||
prefix, sm->authAuthEapLogoffWhileAuthenticating,
|
||||
prefix, sm->authAuthReauthsWhileAuthenticated,
|
||||
prefix, sm->authAuthEapStartsWhileAuthenticated,
|
||||
prefix, sm->authAuthEapLogoffWhileAuthenticated);
|
||||
|
||||
fprintf(f, "%s Backend Authentication:\n"
|
||||
"%s state=%s\n"
|
||||
"%s eapNoReq=%s eapReq=%s eapResp=%s\n"
|
||||
"%s serverTimeout=%d\n"
|
||||
"%s backendResponses=%d\n"
|
||||
"%s backendAccessChallenges=%d\n"
|
||||
"%s backendOtherRequestsToSupplicant=%d\n"
|
||||
"%s backendAuthSuccesses=%d\n"
|
||||
"%s backendAuthFails=%d\n",
|
||||
prefix, prefix,
|
||||
be_auth_state_txt(sm->be_auth_state),
|
||||
prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
|
||||
_SB(sm->eap_if->eapResp),
|
||||
prefix, sm->serverTimeout,
|
||||
prefix, sm->backendResponses,
|
||||
prefix, sm->backendAccessChallenges,
|
||||
prefix, sm->backendOtherRequestsToSupplicant,
|
||||
prefix, sm->backendAuthSuccesses,
|
||||
prefix, sm->backendAuthFails);
|
||||
|
||||
fprintf(f, "%s Reauthentication Timer:\n"
|
||||
"%s state=%s\n"
|
||||
"%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
|
||||
reauth_timer_state_txt(sm->reauth_timer_state), prefix,
|
||||
sm->reAuthPeriod, _SB(sm->reAuthEnabled));
|
||||
|
||||
fprintf(f, "%s Authenticator Key Transmit:\n"
|
||||
"%s state=%s\n", prefix, prefix,
|
||||
auth_key_tx_state_txt(sm->auth_key_tx_state));
|
||||
|
||||
fprintf(f, "%s Key Receive:\n"
|
||||
"%s state=%s\n"
|
||||
"%s rxKey=%s\n", prefix, prefix,
|
||||
key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
|
||||
|
||||
fprintf(f, "%s Controlled Directions:\n"
|
||||
"%s state=%s\n"
|
||||
"%s adminControlledDirections=%s "
|
||||
"operControlledDirections=%s\n"
|
||||
"%s operEdge=%s\n", prefix, prefix,
|
||||
ctrl_dir_state_txt(sm->ctrl_dir_state),
|
||||
prefix, ctrl_dir_txt(sm->adminControlledDirections),
|
||||
ctrl_dir_txt(sm->operControlledDirections),
|
||||
prefix, _SB(sm->operEdge));
|
||||
#undef _SB
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
@echo Nothing to be made.
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue