aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2005-06-05 22:35:03 +0000
committerSam Leffler <sam@FreeBSD.org>2005-06-05 22:35:03 +0000
commit5d48cb5da295e638c3a5c1cb2ad6731da3615f18 (patch)
treea7d225a062cd128980707f3fa918dec2d015c46b
downloadsrc-vendor/hostapd/0.3.7.tar.gz
src-vendor/hostapd/0.3.7.zip
Stripped down import of hostapd v0.3.7vendor/hostapd/0.3.7
-rw-r--r--contrib/hostapd/COPYING340
-rw-r--r--contrib/hostapd/ChangeLog186
-rw-r--r--contrib/hostapd/Makefile233
-rw-r--r--contrib/hostapd/README397
-rw-r--r--contrib/hostapd/accounting.c441
-rw-r--r--contrib/hostapd/accounting.h13
-rw-r--r--contrib/hostapd/aes.c1132
-rw-r--r--contrib/hostapd/aes_wrap.c642
-rw-r--r--contrib/hostapd/aes_wrap.h21
-rw-r--r--contrib/hostapd/ap.h99
-rw-r--r--contrib/hostapd/common.c335
-rw-r--r--contrib/hostapd/common.h222
-rw-r--r--contrib/hostapd/config.c1136
-rw-r--r--contrib/hostapd/config.h177
-rw-r--r--contrib/hostapd/crypto.c71
-rw-r--r--contrib/hostapd/crypto.h8
-rw-r--r--contrib/hostapd/ctrl_iface.c452
-rw-r--r--contrib/hostapd/ctrl_iface.h9
-rw-r--r--contrib/hostapd/defconfig66
-rw-r--r--contrib/hostapd/defs.h14
-rw-r--r--contrib/hostapd/developer.txt219
-rw-r--r--contrib/hostapd/driver.h262
-rw-r--r--contrib/hostapd/driver_test.c78
-rw-r--r--contrib/hostapd/driver_wired.c395
-rw-r--r--contrib/hostapd/eap.c911
-rw-r--r--contrib/hostapd/eap.h83
-rw-r--r--contrib/hostapd/eap_defs.h41
-rw-r--r--contrib/hostapd/eap_gtc.c158
-rw-r--r--contrib/hostapd/eap_i.h110
-rw-r--r--contrib/hostapd/eap_identity.c174
-rw-r--r--contrib/hostapd/eap_md5.c180
-rw-r--r--contrib/hostapd/eap_mschapv2.c483
-rw-r--r--contrib/hostapd/eap_peap.c720
-rw-r--r--contrib/hostapd/eap_sim.c431
-rw-r--r--contrib/hostapd/eap_sim_common.c788
-rw-r--r--contrib/hostapd/eap_sim_common.h101
-rw-r--r--contrib/hostapd/eap_sim_db.c242
-rw-r--r--contrib/hostapd/eap_sim_db.h44
-rw-r--r--contrib/hostapd/eap_tls.c246
-rw-r--r--contrib/hostapd/eap_tls_common.c272
-rw-r--r--contrib/hostapd/eap_tls_common.h47
-rw-r--r--contrib/hostapd/eap_tlv.c248
-rw-r--r--contrib/hostapd/eap_ttls.c1183
-rw-r--r--contrib/hostapd/eap_ttls.h57
-rw-r--r--contrib/hostapd/eapol_sm.c1183
-rw-r--r--contrib/hostapd/eapol_sm.h213
-rw-r--r--contrib/hostapd/eloop.c380
-rw-r--r--contrib/hostapd/eloop.h53
-rw-r--r--contrib/hostapd/hostap_common.h557
-rw-r--r--contrib/hostapd/hostapd.accept5
-rw-r--r--contrib/hostapd/hostapd.c802
-rw-r--r--contrib/hostapd/hostapd.conf293
-rw-r--r--contrib/hostapd/hostapd.deny5
-rw-r--r--contrib/hostapd/hostapd.eap_user45
-rw-r--r--contrib/hostapd/hostapd.h134
-rw-r--r--contrib/hostapd/hostapd.radius_clients4
-rw-r--r--contrib/hostapd/hostapd.sim_db9
-rw-r--r--contrib/hostapd/hostapd.wpa_psk9
-rw-r--r--contrib/hostapd/hostapd_cli.c600
-rw-r--r--contrib/hostapd/hostapd_ctrl.c188
-rw-r--r--contrib/hostapd/hostapd_ctrl.h18
-rw-r--r--contrib/hostapd/iapp.c521
-rw-r--r--contrib/hostapd/iapp.h31
-rw-r--r--contrib/hostapd/ieee802_11.c1217
-rw-r--r--contrib/hostapd/ieee802_11.h99
-rw-r--r--contrib/hostapd/ieee802_11_auth.c447
-rw-r--r--contrib/hostapd/ieee802_11_auth.h16
-rw-r--r--contrib/hostapd/ieee802_1x.c1649
-rw-r--r--contrib/hostapd/ieee802_1x.h84
-rw-r--r--contrib/hostapd/l2_packet.h34
-rw-r--r--contrib/hostapd/madwifi.conf201
-rw-r--r--contrib/hostapd/md5.c355
-rw-r--r--contrib/hostapd/md5.h43
-rw-r--r--contrib/hostapd/ms_funcs.c333
-rw-r--r--contrib/hostapd/ms_funcs.h25
-rw-r--r--contrib/hostapd/radius.c1125
-rw-r--r--contrib/hostapd/radius.h224
-rw-r--r--contrib/hostapd/radius_client.c1016
-rw-r--r--contrib/hostapd/radius_client.h41
-rw-r--r--contrib/hostapd/radius_server.c923
-rw-r--r--contrib/hostapd/radius_server.h45
-rw-r--r--contrib/hostapd/rc4.c63
-rw-r--r--contrib/hostapd/rc4.h7
-rw-r--r--contrib/hostapd/sha1.c910
-rw-r--r--contrib/hostapd/sha1.h50
-rw-r--r--contrib/hostapd/sta_info.c354
-rw-r--r--contrib/hostapd/sta_info.h19
-rw-r--r--contrib/hostapd/tls.h312
-rw-r--r--contrib/hostapd/tls_none.c22
-rw-r--r--contrib/hostapd/tls_openssl.c876
-rw-r--r--contrib/hostapd/version.h6
-rw-r--r--contrib/hostapd/wired.conf38
-rw-r--r--contrib/hostapd/wpa.c2820
-rw-r--r--contrib/hostapd/wpa.h193
94 files changed, 32064 insertions, 0 deletions
diff --git a/contrib/hostapd/COPYING b/contrib/hostapd/COPYING
new file mode 100644
index 000000000000..60549be514af
--- /dev/null
+++ b/contrib/hostapd/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
diff --git a/contrib/hostapd/ChangeLog b/contrib/hostapd/ChangeLog
new file mode 100644
index 000000000000..e4b73ec7e6e7
--- /dev/null
+++ b/contrib/hostapd/ChangeLog
@@ -0,0 +1,186 @@
+ChangeLog for hostapd
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+
+2005-01-23 - v0.3.5
+ * added support for configuring a forced PEAP version based on the
+ Phase 1 identity
+ * fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
+ to terminate authentication
+ * fixed EAP identifier duplicate processing with the new IEEE 802.1X
+ draft
+ * clear accounting data in the driver when starting a new accounting
+ session
+ * driver_madwifi: filter wireless events based on ifindex to allow more
+ than one network interface to be used
+ * fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
+ setting if the packet does not pass MIC verification (e.g., due to
+ incorrect PSK); previously, message 1/4 was not tried again if an
+ invalid message 2/4 was received
+ * fixed reconfiguration of RADIUS client retransmission timer when
+ adding a new message to the pending list; previously, timer was not
+ updated at this point and if there was a pending message with long
+ time for the next retry, the new message needed to wait that long for
+ its first retry, too
+
+2005-01-09 - v0.3.4
+ * added support for configuring multiple allowed EAP types for Phase 2
+ authentication (EAP-PEAP, EAP-TTLS)
+ * fixed EAPOL-Start processing to trigger WPA reauthentication
+ (previously, only EAPOL authentication was done)
+
+2005-01-02 - v0.3.3
+ * added support for EAP-PEAP in the integrated EAP authenticator
+ * added support for EAP-GTC in the integrated EAP authenticator
+ * added support for configuring list of EAP methods for Phase 1 so that
+ the integrated EAP authenticator can, e.g., use the wildcard entry
+ for EAP-TLS and EAP-PEAP
+ * added support for EAP-TTLS in the integrated EAP authenticator
+ * added support for EAP-SIM in the integrated EAP authenticator
+ * added support for using hostapd as a RADIUS authentication server
+ with the integrated EAP authenticator taking care of EAP
+ authentication (new hostapd.conf options: radius_server_clients and
+ radius_server_auth_port); this is not included in default build; use
+ CONFIG_RADIUS_SERVER=y in .config to include
+
+2004-12-19 - v0.3.2
+ * removed 'daemonize' configuration file option since it has not really
+ been used at all for more than year
+ * driver_madwifi: fixed group key setup and added get_ssid method
+ * added support for EAP-MSCHAPv2 in the integrated EAP authenticator
+
+2004-12-12 - v0.3.1
+ * added support for integrated EAP-TLS authentication (new hostapd.conf
+ variables: ca_cert, server_cert, private_key, private_key_passwd);
+ this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
+ external RADIUS server
+ * added support for reading PKCS#12 (PFX) files (as a replacement for
+ PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+ * added support for Acct-{Input,Output}-Gigawords
+ * added support for Event-Timestamp (in RADIUS Accounting-Requests)
+ * added support for RADIUS Authentication Client MIB (RFC2618)
+ * added support for RADIUS Accounting Client MIB (RFC2620)
+ * made EAP re-authentication period configurable (eap_reauth_period)
+ * fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
+ * fixed EAPOL state machine to stop if STA is removed during
+ eapol_sm_step(); this fixes at least one segfault triggering bug with
+ IEEE 802.11i pre-authentication
+ * added support for multiple WPA pre-shared keys (e.g., one for each
+ client MAC address or keys shared by a group of clients);
+ new hostapd.conf field wpa_psk_file for setting path to a text file
+ containing PSKs, see hostapd.wpa_psk for an example
+ * added support for multiple driver interfaces to allow hostapd to be
+ used with other drivers
+ * added wired authenticator driver interface (driver=wired in
+ hostapd.conf, see wired.conf for example configuration)
+ * added madwifi driver interface (driver=madwifi in hostapd.conf, see
+ madwifi.conf for example configuration; Note: include files from
+ madwifi project is needed for building and a configuration file,
+ .config, needs to be created in hostapd directory with
+ CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
+ build)
+ * fixed an alignment issue that could cause SHA-1 to fail on some
+ platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
+ align variables)
+ * fixed RADIUS reconnection after an error in sending interim
+ accounting packets
+ * added hostapd control interface for external programs and an example
+ CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
+ * started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
+ 'hostapd_cli sta <addr>')
+ * finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
+ * added support for strict GTK rekeying (wpa_strict_rekey in
+ hostapd.conf)
+ * updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
+ (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
+ IEEE 802.11F-2003)
+ * added Prism54 driver interface (driver=prism54 in hostapd.conf;
+ note: .config needs to be created in hostapd directory with
+ CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
+ build)
+ * dual-licensed hostapd (GPLv2 and BSD licenses)
+ * fixed RADIUS accounting to generate a new session id for cases where
+ a station reassociates without first being complete deauthenticated
+ * fixed STA disassociation handler to mark next timeout state to
+ deauthenticate the station, i.e., skip long wait for inactivity poll
+ and extra disassociation, if the STA disassociates without
+ deauthenticating
+ * added integrated EAP authenticator that can be used instead of
+ external RADIUS authentication server; currently, only EAP-MD5 is
+ supported, so this cannot yet be used for key distribution; the EAP
+ method interface is generic, though, so adding new EAP methods should
+ be straightforward; new hostapd.conf variables: 'eap_authenticator'
+ and 'eap_user_file'; this obsoletes "minimal authentication server"
+ ('minimal_eap' in hostapd.conf) which is now removed
+ * added support for FreeBSD and driver interface for the BSD net80211
+ layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
+ .config); please note that some of the required kernel mods have not
+ yet been committed
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+ * fixed some accounting cases where Accounting-Start was sent when
+ IEEE 802.1X port was being deauthorized
+
+2004-06-20 - v0.2.3
+ * modified RADIUS client to re-connect the socket in case of certain
+ error codes that are generated when a network interface state is
+ changes (e.g., when IP address changes or the interface is set UP)
+ * fixed couple of cases where EAPOL state for a station was freed
+ twice causing a segfault for hostapd
+ * fixed couple of bugs in processing WPA deauthentication (freed data
+ was used)
+
+2004-05-31 - v0.2.2
+ * fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
+ * fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
+ cases where STAs dropped multicast frames as replay attacks
+ * added support for copying RADIUS Attribute 'Class' from
+ authentication messages into accounting messages
+ * send canned EAP failure if RADIUS server sends Access-Reject without
+ EAP message (previously, Supplicant was not notified in this case)
+ * fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
+ not start EAPOL state machines if the STA selected to use WPA-PSK)
+
+2004-05-06 - v0.2.1
+ * added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
+ - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
+ (i.e., IEEE 802.11i/D3.0)
+ - supports WPA-only, RSN-only, and mixed WPA/RSN mode
+ - both WPA-PSK and WPA-RADIUS/EAP are supported
+ - PMKSA caching and pre-authentication
+ - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
+ wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
+ rsn_preauth, rsn_preauth_interfaces
+ * fixed interim accounting to remove any pending accounting messages
+ to the STA before sending a new one
+
+2004-02-15 - v0.2.0
+ * added support for Acct-Interim-Interval:
+ - draft-ietf-radius-acct-interim-01.txt
+ - use Acct-Interim-Interval attribute from Access-Accept if local
+ 'radius_acct_interim_interval' is not set
+ - allow different update intervals for each STA
+ * fixed event loop to call signal handlers only after returning from
+ the real signal handler
+ * reset sta->timeout_next after successful association to make sure
+ that the previously registered inactivity timer will not remove the
+ STA immediately (e.g., if STA deauthenticates and re-associates
+ before the timer is triggered).
+ * added new hostapd.conf variable, nas_identifier, that can be used to
+ add an optional RADIUS Attribute, NAS-Identifier, into authentication
+ and accounting messages
+ * added support for Accounting-On and Accounting-Off messages
+ * fixed accounting session handling to send Accounting-Start only once
+ per session and not to send Accounting-Stop if the session was not
+ initialized properly
+ * fixed Accounting-Stop statistics in cases where the message was
+ previously sent after the kernel entry for the STA (and/or IEEE
+ 802.1X data) was removed
+
+
+Note:
+
+Older changes up to and including v0.1.0 are included in the ChangeLog
+of the Host AP driver.
diff --git a/contrib/hostapd/Makefile b/contrib/hostapd/Makefile
new file mode 100644
index 000000000000..4c9c49edea8c
--- /dev/null
+++ b/contrib/hostapd/Makefile
@@ -0,0 +1,233 @@
+CC=gcc
+DIR_WPA_SUPPLICANT=.
+DIR_HOSTAP=.
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+
+# Include directories for CVS version
+CFLAGS += -I. -I$(DIR_HOSTAP) -I../utils -I$(DIR_WPA_SUPPLICANT)
+
+# Uncomment following line and set the path to your kernel tree include
+# directory if your C library does not include all header files.
+# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
+
+OBJS = hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.o \
+ common.o ieee802_11.o config.o ieee802_11_auth.o accounting.o \
+ sta_info.o radius_client.o sha1.o wpa.o aes_wrap.o ctrl_iface.o \
+ driver_conf.o
+
+-include .config
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_DRIVER_HOSTAP
+CFLAGS += -DCONFIG_DRIVER_HOSTAP
+OBJS += driver.o
+endif
+
+ifdef CONFIG_DRIVER_WIRED
+CFLAGS += -DCONFIG_DRIVER_WIRED
+OBJS += driver_wired.o
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+CFLAGS += -DCONFIG_DRIVER_MADWIFI
+OBJS += driver_madwifi.o
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_DRIVER_PRISM54
+CFLAGS += -DCONFIG_DRIVER_PRISM54
+OBJS += driver_prism54.o
+endif
+
+ifdef CONFIG_DRIVER_BSD
+CFLAGS += -DCONFIG_DRIVER_BSD
+OBJS += driver_bsd.o
+CONFIG_L2_PACKET=y
+CONFIG_DNET_PCAP=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+CFLAGS += -DCONFIG_DRIVER_TEST
+OBJS += driver_test.o
+endif
+
+ifdef CONFIG_L2_PACKET
+OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet.o
+endif
+
+ifdef CONFIG_DNET_PCAP
+CFLAGS += -DUSE_DNET_PCAP
+LIBS +=-ldnet -lpcap
+endif
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_MD5
+OBJS += eap_md5.o
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_TLS
+OBJS += eap_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_PEAP
+OBJS += eap_peap.o
+TLS_FUNCS=y
+CONFIG_EAP_TLV=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_TTLS
+OBJS += eap_ttls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += eap_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_GTC
+OBJS += eap_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SIM
+OBJS += eap_sim.o $(DIR_WPA_SUPPLICANT)/eap_sim_common.o
+# Example EAP-SIM interface for GSM authentication. This can be replaced with
+# another file implementating the interface specified in eap_sim_db.h.
+OBJS += eap_sim_db.o
+endif
+
+ifdef CONFIG_EAP_TLV
+CFLAGS += -DEAP_TLV
+OBJS += eap_tlv.o
+endif
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_AUTHENTICATOR
+OBJS += eap.o eap_identity.o
+endif
+
+ifdef TLS_FUNCS
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += eap_tls_common.o $(DIR_WPA_SUPPLICANT)/tls_openssl.o
+LIBS += -lssl -lcrypto
+LIBS_p += -lcrypto
+else
+OBJS += $(DIR_WPA_SUPPLICANT)/tls_none.o
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+ifndef TLS_FUNCS
+LIBS += -lcrypto
+endif
+OBJS += $(DIR_WPA_SUPPLICANT)/ms_funcs.o $(DIR_WPA_SUPPLICANT)/crypto.o
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += radius_server.o
+endif
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+verify_config:
+ @if [ ! -r .config ]; then \
+ echo 'Building hostapd requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+
+install: all
+ for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
+
+hostapd: $(OBJS)
+ $(CC) -o hostapd $(OBJS) $(LIBS)
+
+driver_conf.c: Makefile .config
+ rm -f driver_conf.c
+ echo '/* THIS FILE AUTOMATICALLY GENERATED, DO NOT EDIT! */' \
+ > driver_conf.c
+ echo '#include <stdlib.h>' >> driver_conf.c
+ echo '#include <stdio.h>' >> driver_conf.c
+ echo '#include <sys/types.h>' >> driver_conf.c
+ echo '#include <netinet/in.h>' >> driver_conf.c
+ echo '#include "hostapd.h"' >> driver_conf.c
+ echo '#include "driver.h"' >> driver_conf.c
+ifdef CONFIG_DRIVER_HOSTAP
+ echo "void hostap_driver_register(void);" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_WIRED
+ echo "void wired_driver_register(void);" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_MADWIFI
+ echo "void madwifi_driver_register(void);" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_PRISM54
+ echo "void prism54_driver_register(void);" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_BSD
+ echo "void bsd_driver_register(void);" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_TEST
+ echo "void test_driver_register(void);" >> driver_conf.c
+endif
+ echo 'void register_drivers(void) {' >> driver_conf.c
+ifdef CONFIG_DRIVER_HOSTAP
+ echo "hostap_driver_register();" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_WIRED
+ echo "wired_driver_register();" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_MADWIFI
+ echo "madwifi_driver_register();" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_PRISM54
+ echo "prism54_driver_register();" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_BSD
+ echo "bsd_driver_register();" >> driver_conf.c
+endif
+ifdef CONFIG_DRIVER_TEST
+ echo "test_driver_register();" >> driver_conf.c
+endif
+ echo '}' >> driver_conf.c
+
+hostapd_cli: hostapd_cli.o hostapd_ctrl.o
+ $(CC) -o hostapd_cli hostapd_cli.o hostapd_ctrl.o
+
+clean:
+ rm -f core *~ *.o hostapd *.d driver_conf.c
+
+-include $(OBJS:%.o=%.d)
diff --git a/contrib/hostapd/README b/contrib/hostapd/README
new file mode 100644
index 000000000000..18fc1793cac8
--- /dev/null
+++ b/contrib/hostapd/README
@@ -0,0 +1,397 @@
+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
+ Authenticator and RADIUS authentication server
+================================================================
+
+Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option. Please note that
+some of the driver interface implementations (driver_*.c) may be
+licensed under a different license.
+
+
+
+License
+-------
+
+GPL v2:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+(this copy of the license is in COPYING file)
+
+
+Alternatively, this software may be distributed under the terms of BSD
+license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Introduction
+============
+
+Originally, hostapd was an optional user space component for Host AP
+driver. It adds more features to the basic IEEE 802.11 management
+included in the kernel driver: using external RADIUS authentication
+server for MAC address based access control, IEEE 802.1X Authenticator
+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
+Authenticator and dynamic TKIP/CCMP keying.
+
+The current version includes support for other drivers, an integrated
+EAP authenticator (i.e., allow full authentication without requiring
+an external RADIUS authentication server), and RADIUS authentication
+server for EAP authentication.
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- drivers:
+ Host AP driver for Prism2/2.5/3.
+ (http://hostap.epitest.fi/)
+ Please note that station firmware version needs to be 1.7.0 or newer
+ to work in WPA mode.
+
+ madwifi driver for cards based on Atheros chip set (ar521x)
+ (http://sourceforge.net/projects/madwifi/)
+ Please note that you will need to modify the hostapd Makefile
+ to use correct path for madwifi driver root directory
+ (CFLAGS += -I../head line in Makefile).
+
+ Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
+ (http://www.prism54.org/)
+
+ Any wired Ethernet driver for wired IEEE 802.1X authentication
+ (experimental code)
+
+ FreeBSD -current (with some kernel mods that have not yet been
+ committed when hostapd v0.3.0 was released)
+ BSD net80211 layer (e.g., Atheros driver)
+
+
+Build configuration
+-------------------
+
+In order to be able to build hostapd, you will need to create a build
+time configuration file, .config that selects which optional
+components are included. See defconfig file for example configuration
+and list of available options.
+
+
+
+IEEE 802.1X
+===========
+
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. In case of IEEE 802.11 networks, a "virtual port" is used
+between each associated station and the AP. IEEE 802.11 specifies
+minimal authentication mechanism for stations, whereas IEEE 802.1X
+introduces a extensible mechanism for authenticating and authorizing
+users.
+
+IEEE 802.1X uses elements called Supplicant, Authenticator, Port
+Access Entity, and Authentication Server. Supplicant is a component in
+a station and it performs the authentication with the Authentication
+Server. An access point includes an Authenticator that relays the packets
+between a Supplicant and an Authentication Server. In addition, it has a
+Port Access Entity (PAE) with Authenticator functionality for
+controlling the virtual port authorization, i.e., whether to accept
+packets from or to the station.
+
+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
+between a Supplicant and an Authenticator are sent using EAP over LAN
+(EAPOL) and the Authenticator relays these frames to the Authentication
+Server (and similarly, relays the messages from the Authentication
+Server to the Supplicant). The Authentication Server can be colocated with the
+Authenticator, in which case there is no need for additional protocol
+for EAP frame transmission. However, a more common configuration is to
+use an external Authentication Server and encapsulate EAP frame in the
+frames used by that server. RADIUS is suitable for this, but IEEE
+802.1X would also allow other mechanisms.
+
+Host AP driver includes PAE functionality in the kernel driver. It
+is a relatively simple mechanism for denying normal frames going to
+or coming from an unauthorized port. PAE allows IEEE 802.1X related
+frames to be passed between the Supplicant and the Authenticator even
+on an unauthorized port.
+
+User space daemon, hostapd, includes Authenticator functionality. It
+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
+device that is also used with IEEE 802.11 management frames. The
+frames to the Supplicant are sent using the same device.
+
+hostapd includes a minimal colocated Authentication Server for testing
+purposes. It only requests the identity of the Supplicant and
+authorizes any host that is able to send a valid EAP Response
+frame. This can be used for quick testing since it does not require an
+external Authentication Server, but it should not be used for any real
+authentication purposes since no keys are required and anyone can
+authenticate.
+
+The normal configuration of the Authenticator would use an external
+Authentication Server. hostapd supports RADIUS encapsulation of EAP
+packets, so the Authentication Server should be a RADIUS server, like
+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
+relays the frames between the Supplicant and the Authentication
+Server. It also controls the PAE functionality in the kernel driver by
+controlling virtual port authorization, i.e., station-AP
+connection, based on the IEEE 802.1X state.
+
+When a station would like to use the services of an access point, it
+will first perform IEEE 802.11 authentication. This is normally done
+with open systems authentication, so there is no security. After
+this, IEEE 802.11 association is performed. If IEEE 802.1X is
+configured to be used, the virtual port for the station is set in
+Unauthorized state and only IEEE 802.1X frames are accepted at this
+point. The Authenticator will then ask the Supplicant to authenticate
+with the Authentication Server. After this is completed successfully,
+the virtual port is set to Authorized state and frames from and to the
+station are accepted.
+
+Host AP configuration for IEEE 802.1X
+-------------------------------------
+
+The user space daemon has its own configuration file that can be used to
+define AP options. Distribution package contains an example
+configuration file (hostapd/hostapd.conf) that can be used as a basis
+for configuration. It includes examples of all supported configuration
+options and short description of each option. hostapd should be started
+with full path to the configuration file as the command line argument,
+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
+LAN card, you can use one hostapd process for multiple interfaces by
+giving a list of configuration files (one per interface) in the command
+line.
+
+hostapd includes a minimal co-located IEEE 802.1X server which can be
+used to test IEEE 802.1X authentication. However, it should not be
+used in normal use since it does not provide any security. This can be
+configured by setting ieee8021x and minimal_eap options in the
+configuration file.
+
+An external Authentication Server (RADIUS) is configured with
+auth_server_{addr,port,shared_secret} options. In addition,
+ieee8021x and own_ip_addr must be set for this mode. With such
+configuration, the co-located Authentication Server is not used and EAP
+frames will be relayed using EAPOL between the Supplicant and the
+Authenticator and RADIUS encapsulation between the Authenticator and
+the Authentication Server. Other than this, the functionality is similar
+to the case with the co-located Authentication Server.
+
+Authentication Server and Supplicant
+------------------------------------
+
+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
+Authentication Server with hostapd Authenticator. FreeRADIUS
+(http://www.freeradius.org/) has been successfully tested with hostapd
+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
+XP Supplicants. EAP/TLS was used with Xsupplicant and
+EAP/MD5-Challenge with Windows XP.
+
+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
+Cisco access point with Host AP driver, hostapd daemon, and a Prism2
+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
+EAP/TLS use with WinXP Supplicant.
+
+Automatic WEP key configuration
+-------------------------------
+
+EAP/TLS generates a session key that can be used to send WEP keys from
+an AP to authenticated stations. The Authenticator in hostapd can be
+configured to automatically select a random default/broadcast key
+(shared by all authenticated stations) with wep_key_len_broadcast
+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
+wep_key_len_unicast option can be used to configure individual unicast
+keys for stations. This requires support for individual keys in the
+station driver.
+
+WEP keys can be automatically updated by configuring rekeying. This
+will improve security of the network since same WEP key will only be
+used for a limited period of time. wep_rekey_period option sets the
+interval for rekeying in seconds.
+
+
+WPA/WPA2
+========
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proved to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Testing for WPA2 is likely to start during the second half of 2004.
+
+hostapd configuration for WPA/WPA2
+----------------------------------
+
+TODO
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds.
+#wpa_group_rekey=600
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
diff --git a/contrib/hostapd/accounting.c b/contrib/hostapd/accounting.c
new file mode 100644
index 000000000000..188f8598b0b1
--- /dev/null
+++ b/contrib/hostapd/accounting.c
@@ -0,0 +1,441 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+
+#include "hostapd.h"
+#include "radius.h"
+#include "radius_client.h"
+#include "eloop.h"
+#include "accounting.h"
+#include "ieee802_1x.h"
+#include "driver.h"
+
+
+/* Default interval in seconds for polling TX/RX octets from the driver if
+ * STA is not using interim accounting. This detects wrap arounds for
+ * input/output octets and updates Acct-{Input,Output}-Gigawords. */
+#define ACCT_DEFAULT_UPDATE_INTERVAL 300
+
+static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
+ int status_type)
+{
+ struct radius_msg *msg;
+ char buf[128];
+ u8 *val;
+ size_t len;
+
+ 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));
+
+ 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, 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) {
+ snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ val = (u8 *) buf;
+ len = strlen(buf);
+ }
+
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
+ len)) {
+ printf("Could not add User-Name\n");
+ goto fail;
+ }
+ }
+
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ (u8 *) &hapd->conf->own_ip_addr, 4)) {
+ printf("Could not add NAS-IP-Address\n");
+ goto fail;
+ }
+
+ if (hapd->conf->nas_identifier &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ (u8 *) hapd->conf->nas_identifier,
+ 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;
+ }
+
+ snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
+ MAC2STR(hapd->own_addr), hapd->conf->ssid);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ (u8 *) buf, strlen(buf))) {
+ printf("Could not add Called-Station-Id\n");
+ goto fail;
+ }
+
+ if (sta) {
+ 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, 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;
+ }
+
+ snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ (u8 *) buf, strlen(buf))) {
+ printf("Could not add Connect-Info\n");
+ goto fail;
+ }
+
+ val = ieee802_1x_get_radius_class(sta->eapol_sm, &len);
+ if (val &&
+ !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);
+ free(msg);
+ return NULL;
+}
+
+
+static int accounting_sta_update_stats(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct hostap_sta_driver_data *data)
+{
+ if (hostapd_read_sta_data(hapd, data, sta->addr))
+ return -1;
+
+ if (sta->last_rx_bytes > data->rx_bytes)
+ sta->acct_input_gigawords++;
+ if (sta->last_tx_bytes > data->tx_bytes)
+ sta->acct_output_gigawords++;
+ sta->last_rx_bytes = data->rx_bytes;
+ sta->last_tx_bytes = data->tx_bytes;
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
+ "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
+ "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
+ sta->last_rx_bytes, sta->acct_input_gigawords,
+ sta->last_tx_bytes, sta->acct_output_gigawords);
+
+ return 0;
+}
+
+
+static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
+{
+ hostapd *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);
+}
+
+
+void accounting_sta_start(hostapd *hapd, struct sta_info *sta)
+{
+ struct radius_msg *msg;
+ int interval;
+
+ if (sta->acct_session_started)
+ return;
+
+ time(&sta->acct_session_start);
+ sta->last_rx_bytes = sta->last_tx_bytes = 0;
+ sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+ hostapd_sta_clear_stats(hapd, sta->addr);
+
+ if (!hapd->conf->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;
+}
+
+
+void accounting_sta_report(hostapd *hapd, struct sta_info *sta, int stop)
+{
+ struct radius_msg *msg;
+ int cause = sta->acct_terminate_cause;
+ struct hostap_sta_driver_data data;
+ u32 gigawords;
+
+ if (!hapd->conf->acct_server)
+ return;
+
+ msg = accounting_msg(hapd, sta,
+ stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
+ RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
+ if (!msg) {
+ printf("Could not create RADIUS Accounting message\n");
+ return;
+ }
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
+ time(NULL) - sta->acct_session_start)) {
+ printf("Could not add Acct-Session-Time\n");
+ goto fail;
+ }
+
+ if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_PACKETS,
+ data.rx_packets)) {
+ printf("Could not add Acct-Input-Packets\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
+ data.tx_packets)) {
+ printf("Could not add Acct-Output-Packets\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_OCTETS,
+ data.rx_bytes)) {
+ printf("Could not add Acct-Input-Octets\n");
+ goto fail;
+ }
+ gigawords = sta->acct_input_gigawords;
+#if __WORDSIZE == 64
+ gigawords += data.rx_bytes >> 32;
+#endif
+ if (gigawords &&
+ !radius_msg_add_attr_int32(
+ msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+ gigawords)) {
+ printf("Could not add Acct-Input-Gigawords\n");
+ goto fail;
+ }
+ if (!radius_msg_add_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
+ data.tx_bytes)) {
+ printf("Could not add Acct-Output-Octets\n");
+ goto fail;
+ }
+ gigawords = sta->acct_output_gigawords;
+#if __WORDSIZE == 64
+ gigawords += data.tx_bytes >> 32;
+#endif
+ if (gigawords &&
+ !radius_msg_add_attr_int32(
+ msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+ gigawords)) {
+ printf("Could not add Acct-Output-Gigawords\n");
+ goto fail;
+ }
+ }
+
+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ time(NULL))) {
+ printf("Could not add Event-Timestamp\n");
+ goto fail;
+ }
+
+ if (eloop_terminated())
+ cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
+
+ if (stop && cause &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+ cause)) {
+ printf("Could not add Acct-Terminate-Cause\n");
+ goto fail;
+ }
+
+ radius_client_send(hapd->radius, msg,
+ stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+ sta->addr);
+ return;
+
+ fail:
+ radius_msg_free(msg);
+ free(msg);
+}
+
+
+void accounting_sta_interim(hostapd *hapd, struct sta_info *sta)
+{
+ if (sta->acct_session_started)
+ accounting_sta_report(hapd, sta, 0);
+}
+
+
+void accounting_sta_stop(hostapd *hapd, struct sta_info *sta)
+{
+ if (sta->acct_session_started) {
+ accounting_sta_report(hapd, sta, 1);
+ eloop_cancel_timeout(accounting_interim_update, hapd, sta);
+ sta->acct_session_started = 0;
+ }
+}
+
+
+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;
+}
+
+
+/* Process the RADIUS frames from Accounting Server */
+static RadiusRxResult
+accounting_receive(struct radius_msg *msg, struct radius_msg *req,
+ u8 *shared_secret, size_t shared_secret_len, void *data)
+{
+ if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
+ printf("Unknown RADIUS message code\n");
+ return RADIUS_RX_UNKNOWN;
+ }
+
+ if (radius_msg_verify_acct(msg, shared_secret, shared_secret_len, req))
+ {
+ 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->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);
+ free(msg);
+ return;
+ }
+
+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
+}
+
+
+int accounting_init(hostapd *hapd)
+{
+ /* Acct-Session-Id should be unique over reboots. If reliable clock is
+ * not available, this could be replaced with reboot counter, etc. */
+ hapd->acct_session_id_hi = time(NULL);
+
+ if (radius_client_register(hapd->radius, RADIUS_ACCT,
+ accounting_receive, hapd))
+ return -1;
+
+ accounting_report_state(hapd, 1);
+
+ return 0;
+}
+
+
+void accounting_deinit(hostapd *hapd)
+{
+ accounting_report_state(hapd, 0);
+}
diff --git a/contrib/hostapd/accounting.h b/contrib/hostapd/accounting.h
new file mode 100644
index 000000000000..8af3eac59cb5
--- /dev/null
+++ b/contrib/hostapd/accounting.h
@@ -0,0 +1,13 @@
+#ifndef ACCOUNTING_H
+#define ACCOUNTING_H
+
+
+void accounting_sta_start(hostapd *hapd, struct sta_info *sta);
+void accounting_sta_interim(hostapd *hapd, struct sta_info *sta);
+void accounting_sta_stop(hostapd *hapd, struct sta_info *sta);
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+int accounting_init(hostapd *hapd);
+void accounting_deinit(hostapd *hapd);
+
+
+#endif /* ACCOUNTING_H */
diff --git a/contrib/hostapd/aes.c b/contrib/hostapd/aes.c
new file mode 100644
index 000000000000..eabebd074653
--- /dev/null
+++ b/contrib/hostapd/aes.c
@@ -0,0 +1,1132 @@
+/*
+ * Modifications to public domain implementation:
+ * - support only 128-bit keys
+ * - cleanup
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.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.
+ */
+
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define FULL_UNROLL
+
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
+{
+ int i;
+ u32 temp;
+
+ rk[0] = GETU32(cipherKey );
+ rk[1] = GETU32(cipherKey + 4);
+ rk[2] = GETU32(cipherKey + 8);
+ rk[3] = GETU32(cipherKey + 12);
+ for (i = 0; i < 10; i++) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ rk += 4;
+ }
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+{
+ int Nr = 10, i, j;
+ u32 temp;
+
+ /* expand the cipher key: */
+ rijndaelKeySetupEnc(rk, cipherKey);
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the
+ * first and the last: */
+ for (i = 1; i < Nr; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+}
+
+void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+ int Nr = 10;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(pt ) ^ rk[0];
+ s1 = GETU32(pt + 4) ^ rk[1];
+ s2 = GETU32(pt + 8) ^ rk[2];
+ s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+ int Nr = 10;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
diff --git a/contrib/hostapd/aes_wrap.c b/contrib/hostapd/aes_wrap.c
new file mode 100644
index 000000000000..dbcc136517e7
--- /dev/null
+++ b/contrib/hostapd/aes_wrap.c
@@ -0,0 +1,642 @@
+/*
+ * 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-2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "common.h"
+#include "aes_wrap.h"
+
+#ifdef EAP_TLS_FUNCS
+
+#include <openssl/aes.h>
+
+#else /* EAP_TLS_FUNCS */
+
+#include "aes.c"
+
+struct aes_key_st {
+ u32 rk[44];
+};
+typedef struct aes_key_st AES_KEY;
+
+#define AES_set_encrypt_key(userKey, bits, key) \
+ rijndaelKeySetupEnc((key)->rk, (userKey))
+#define AES_set_decrypt_key(userKey, bits, key) \
+ rijndaelKeySetupDec((key)->rk, (userKey))
+#define AES_encrypt(in, out, key) \
+ rijndaelEncrypt((key)->rk, in, out)
+#define AES_decrypt(in, out, key) \
+ rijndaelDecrypt((key)->rk, in, out)
+
+#endif /* EAP_TLS_FUNCS */
+
+
+/*
+ * @kek: key encryption key (KEK)
+ * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @plain: plaintext key to be wrapped, n * 64 bit
+ * @cipher: wrapped key, (n + 1) * 64 bit
+ */
+void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
+{
+ u8 *a, *r, b[16];
+ int i, j;
+ AES_KEY key;
+
+ a = cipher;
+ r = cipher + 8;
+
+ /* 1) Initialize variables. */
+ memset(a, 0xa6, 8);
+ memcpy(r, plain, 8 * n);
+
+ AES_set_encrypt_key(kek, 128, &key);
+
+ /* 2) Calculate intermediate values.
+ * For j = 0 to 5
+ * For i=1 to n
+ * B = AES(K, A | R[i])
+ * A = MSB(64, B) ^ t where t = (n*j)+i
+ * R[i] = LSB(64, B)
+ */
+ for (j = 0; j <= 5; j++) {
+ r = cipher + 8;
+ for (i = 1; i <= n; i++) {
+ memcpy(b, a, 8);
+ memcpy(b + 8, r, 8);
+ AES_encrypt(b, b, &key);
+ memcpy(a, b, 8);
+ a[7] ^= n * j + i;
+ memcpy(r, b + 8, 8);
+ r += 8;
+ }
+ }
+
+ /* 3) Output the results.
+ *
+ * These are already in @cipher due to the location of temporary
+ * variables.
+ */
+}
+
+
+/*
+ * @kek: key encryption key (KEK)
+ * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
+ * @plain: plaintext key, n * 64 bit
+ */
+int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
+{
+ u8 a[8], *r, b[16];
+ int i, j;
+ AES_KEY key;
+
+ /* 1) Initialize variables. */
+ memcpy(a, cipher, 8);
+ r = plain;
+ memcpy(r, cipher + 8, 8 * n);
+
+ AES_set_decrypt_key(kek, 128, &key);
+
+ /* 2) Compute intermediate values.
+ * For j = 5 to 0
+ * For i = n to 1
+ * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+ * A = MSB(64, B)
+ * R[i] = LSB(64, B)
+ */
+ for (j = 5; j >= 0; j--) {
+ r = plain + (n - 1) * 8;
+ for (i = n; i >= 1; i--) {
+ memcpy(b, a, 8);
+ b[7] ^= n * j + i;
+
+ memcpy(b + 8, r, 8);
+ AES_decrypt(b, b, &key);
+ memcpy(a, b, 8);
+ memcpy(r, b + 8, 8);
+ r -= 8;
+ }
+ }
+
+ /* 3) Output results.
+ *
+ * These are already in @plain due to the location of temporary
+ * variables. Just verify that the IV matches with the expected value.
+ */
+ for (i = 0; i < 8; i++) {
+ if (a[i] != 0xa6)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#define BLOCK_SIZE 16
+
+static void gf_mulx(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
+ const u8 *pos = data;
+ int i;
+ size_t left = data_len;
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memset(cbc, 0, BLOCK_SIZE);
+
+ while (left >= BLOCK_SIZE) {
+ for (i = 0; i < BLOCK_SIZE; i++)
+ cbc[i] ^= *pos++;
+ if (left > BLOCK_SIZE)
+ AES_encrypt(cbc, cbc, &akey);
+ left -= BLOCK_SIZE;
+ }
+
+ memset(pad, 0, BLOCK_SIZE);
+ AES_encrypt(pad, pad, &akey);
+ gf_mulx(pad);
+
+ if (left || data_len == 0) {
+ for (i = 0; i < left; i++)
+ cbc[i] ^= *pos++;
+ cbc[left] ^= 0x80;
+ gf_mulx(pad);
+ }
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ pad[i] ^= cbc[i];
+ AES_encrypt(pad, mac, &akey);
+}
+
+
+void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+{
+ AES_KEY akey;
+ AES_set_encrypt_key(key, 128, &akey);
+ AES_encrypt(in, out, &akey);
+}
+
+
+void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
+{
+ AES_KEY akey;
+ size_t len, left = data_len;
+ int i;
+ u8 *pos = data;
+ u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memcpy(counter, nonce, BLOCK_SIZE);
+
+ while (left > 0) {
+ AES_encrypt(counter, buf, &akey);
+
+ len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
+ for (i = 0; i < len; i++)
+ pos[i] ^= buf[i];
+ pos += len;
+ left -= len;
+
+ for (i = BLOCK_SIZE - 1; i >= 0; i--) {
+ counter[i]++;
+ if (counter[i])
+ break;
+ }
+ }
+}
+
+
+int 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)
+{
+ u8 *buf;
+ size_t buf_len;
+ u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE];
+ int i;
+
+ if (nonce_len > data_len)
+ buf_len = nonce_len;
+ else
+ buf_len = data_len;
+ if (hdr_len > buf_len)
+ buf_len = hdr_len;
+ buf_len += 16;
+
+ buf = malloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ memset(buf, 0, 15);
+
+ buf[15] = 0;
+ memcpy(buf + 16, nonce, nonce_len);
+ omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
+
+ buf[15] = 1;
+ memcpy(buf + 16, hdr, hdr_len);
+ omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
+
+ aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+ buf[15] = 2;
+ memcpy(buf + 16, data, data_len);
+ omac1_aes_128(key, buf, 16 + data_len, data_mac);
+
+ free(buf);
+
+ for (i = 0; i < BLOCK_SIZE; i++)
+ tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
+
+ return 0;
+}
+
+
+int 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)
+{
+ u8 *buf;
+ size_t buf_len;
+ u8 nonce_mac[BLOCK_SIZE], hdr_mac[BLOCK_SIZE], data_mac[BLOCK_SIZE];
+ int i;
+
+ if (nonce_len > data_len)
+ buf_len = nonce_len;
+ else
+ buf_len = data_len;
+ if (hdr_len > buf_len)
+ buf_len = hdr_len;
+ buf_len += 16;
+
+ buf = malloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ memset(buf, 0, 15);
+
+ buf[15] = 0;
+ memcpy(buf + 16, nonce, nonce_len);
+ omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
+
+ buf[15] = 1;
+ memcpy(buf + 16, hdr, hdr_len);
+ omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
+
+ buf[15] = 2;
+ memcpy(buf + 16, data, data_len);
+ omac1_aes_128(key, buf, 16 + data_len, data_mac);
+
+ free(buf);
+
+ for (i = 0; i < BLOCK_SIZE; i++) {
+ if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
+ return -2;
+ }
+
+ aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+
+ return 0;
+}
+
+
+void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE];
+ u8 *pos = data;
+ int i, j, blocks;
+
+ AES_set_encrypt_key(key, 128, &akey);
+ memcpy(cbc, iv, BLOCK_SIZE);
+
+ blocks = data_len / BLOCK_SIZE;
+ for (i = 0; i < blocks; i++) {
+ for (j = 0; j < BLOCK_SIZE; j++)
+ cbc[j] ^= pos[j];
+ AES_encrypt(cbc, cbc, &akey);
+ memcpy(pos, cbc, BLOCK_SIZE);
+ pos += BLOCK_SIZE;
+ }
+}
+
+
+void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len)
+{
+ AES_KEY akey;
+ u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE];
+ u8 *pos = data;
+ int i, j, blocks;
+
+ AES_set_decrypt_key(key, 128, &akey);
+ memcpy(cbc, iv, BLOCK_SIZE);
+
+ blocks = data_len / BLOCK_SIZE;
+ for (i = 0; i < blocks; i++) {
+ memcpy(tmp, pos, BLOCK_SIZE);
+ AES_decrypt(pos, pos, &akey);
+ for (j = 0; j < BLOCK_SIZE; j++)
+ pos[j] ^= cbc[j];
+ memcpy(cbc, tmp, BLOCK_SIZE);
+ pos += BLOCK_SIZE;
+ }
+}
+
+
+#ifdef TEST_MAIN
+
+#ifdef __i386__
+#define rdtscll(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+
+static void test_aes_perf(void)
+{
+ const int num_iters = 10;
+ int i;
+ unsigned int start, end;
+ AES_KEY akey;
+ u8 key[16], pt[16], ct[16];
+
+ printf("keySetupEnc:");
+ for (i = 0; i < num_iters; i++) {
+ rdtscll(start);
+ AES_set_encrypt_key(key, 128, &akey);
+ rdtscll(end);
+ printf(" %d", end - start);
+ }
+ printf("\n");
+
+ printf("Encrypt:");
+ for (i = 0; i < num_iters; i++) {
+ rdtscll(start);
+ AES_encrypt(pt, ct, &akey);
+ rdtscll(end);
+ printf(" %d", end - start);
+ }
+ printf("\n");
+}
+#endif /* __i386__ */
+
+
+static int test_eax(void)
+{
+ u8 msg[] = { 0xF7, 0xFB };
+ u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+ 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+ u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+ 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+ u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+ u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+ 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+ 0x67, 0xE5 };
+ u8 data[sizeof(msg)], tag[BLOCK_SIZE];
+
+ memcpy(data, msg, sizeof(msg));
+ if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ printf("AES-128 EAX mode encryption failed\n");
+ return 1;
+ }
+ if (memcmp(data, cipher, sizeof(data)) != 0) {
+ printf("AES-128 EAX mode encryption returned invalid cipher "
+ "text\n");
+ return 1;
+ }
+ if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
+ printf("AES-128 EAX mode encryption returned invalid tag\n");
+ return 1;
+ }
+
+ if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ printf("AES-128 EAX mode decryption failed\n");
+ return 1;
+ }
+ if (memcmp(data, msg, sizeof(data)) != 0) {
+ printf("AES-128 EAX mode decryption returned invalid plain "
+ "text\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_cbc(void)
+{
+ struct cbc_test_vector {
+ u8 key[16];
+ u8 iv[16];
+ u8 plain[32];
+ u8 cipher[32];
+ size_t len;
+ } vectors[] = {
+ {
+ { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ "Single block msg",
+ { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+ 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+ 16
+ },
+ {
+ { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+ 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+ 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+ 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+ 32
+ }
+ };
+ int i, ret = 0;
+ u8 *buf;
+
+ for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
+ struct cbc_test_vector *tv = &vectors[i];
+ buf = malloc(tv->len);
+ if (buf == NULL) {
+ ret++;
+ break;
+ }
+ memcpy(buf, tv->plain, tv->len);
+ aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
+ if (memcmp(buf, tv->cipher, tv->len) != 0) {
+ printf("AES-CBC encrypt %d failed\n", i);
+ ret++;
+ }
+ memcpy(buf, tv->cipher, tv->len);
+ aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
+ if (memcmp(buf, tv->plain, tv->len) != 0) {
+ printf("AES-CBC decrypt %d failed\n", i);
+ ret++;
+ }
+ free(buf);
+ }
+
+ return ret;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ */
+
+struct omac1_test_vector {
+ u8 k[16];
+ u8 msg[64];
+ int msg_len;
+ u8 tag[16];
+};
+
+static struct omac1_test_vector test_vectors[] =
+{
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { },
+ 0,
+ { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ 16,
+ { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+ 40,
+ { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ 64,
+ { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+ },
+};
+
+
+int main(int argc, char *argv[])
+{
+ u8 kek[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ u8 plain[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt[] = {
+ 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+ 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+ 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+ };
+ u8 result[24];
+ int ret = 0, i;
+ struct omac1_test_vector *tv;
+
+ aes_wrap(kek, 2, plain, result);
+ if (memcmp(result, crypt, 24) != 0) {
+ printf("AES-WRAP-128-128 failed\n");
+ ret++;
+ }
+ if (aes_unwrap(kek, 2, crypt, result)) {
+ printf("AES-UNWRAP-128-128 reported failure\n");
+ ret++;
+ }
+ if (memcmp(result, plain, 16) != 0) {
+ int i;
+ printf("AES-UNWRAP-128-128 failed\n");
+ ret++;
+ for (i = 0; i < 16; i++)
+ printf(" %02x", result[i]);
+ printf("\n");
+ }
+
+#ifdef __i386__
+ test_aes_perf();
+#endif /* __i386__ */
+
+ for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
+ tv = &test_vectors[i];
+ omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
+ if (memcmp(result, tv->tag, 16) != 0) {
+ printf("OMAC1-AES-128 test vector %d failed\n", i);
+ ret++;
+ }
+ }
+
+ ret += test_eax();
+
+ ret += test_cbc();
+
+ if (ret)
+ printf("FAILED!\n");
+
+ return ret;
+}
+#endif /* TEST_MAIN */
diff --git a/contrib/hostapd/aes_wrap.h b/contrib/hostapd/aes_wrap.h
new file mode 100644
index 000000000000..70e83ea09d73
--- /dev/null
+++ b/contrib/hostapd/aes_wrap.h
@@ -0,0 +1,21 @@
+#ifndef AES_WRAP_H
+#define AES_WRAP_H
+
+void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher);
+int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain);
+void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
+void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len);
+int 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 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);
+void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
+void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
+
+#endif /* AES_WRAP_H */
diff --git a/contrib/hostapd/ap.h b/contrib/hostapd/ap.h
new file mode 100644
index 000000000000..e874ffd2b237
--- /dev/null
+++ b/contrib/hostapd/ap.h
@@ -0,0 +1,99 @@
+#ifndef AP_H
+#define AP_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_PREAUTH BIT(7)
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+#define WLAN_RATE_COUNT 4
+
+/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
+ * but some pre-standard IEEE 802.11g products use longer elements. */
+#define WLAN_SUPP_RATES_MAX 32
+
+
+struct sta_info {
+ struct sta_info *next; /* next entry in sta list */
+ struct sta_info *hnext; /* next entry in hash table list */
+ u8 addr[6];
+ u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+ u32 flags;
+ u16 capability;
+ u16 listen_interval; /* or beacon_int for APs */
+ u8 supported_rates[WLAN_SUPP_RATES_MAX];
+ u8 tx_supp_rates;
+
+ 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 */
+
+ int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+ struct wpa_state_machine *wpa_sm;
+ enum {
+ WPA_VERSION_NO_WPA = 0 /* WPA not used */,
+ WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
+ WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
+ } wpa;
+ int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
+ struct rsn_pmksa_cache *pmksa;
+ struct rsn_preauth_interface *preauth_iface;
+ u8 req_replay_counter[8 /* WPA_REPLAY_COUNTER_LEN */];
+ int req_replay_counter_used;
+ u32 dot11RSNAStatsTKIPLocalMICFailures;
+ u32 dot11RSNAStatsTKIPRemoteMICFailures;
+};
+
+
+#define MAX_STA_COUNT 1024
+
+/* Maximum number of AIDs to use for STAs; must be 2007 or lower
+ * (8802.11 limitation) */
+#define MAX_AID_TABLE_SIZE 128
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
+ * passed since last received frame from the station, a nullfunc data frame is
+ * sent to the station. If this frame is not acknowledged and no other frames
+ * have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
+#define AP_MAX_INACTIVITY (5 * 60)
+#define AP_DISASSOC_DELAY (1)
+#define AP_DEAUTH_DELAY (1)
+
+#endif /* AP_H */
diff --git a/contrib/hostapd/common.c b/contrib/hostapd/common.c
new file mode 100644
index 000000000000..071ffe87c1d1
--- /dev/null
+++ b/contrib/hostapd/common.c
@@ -0,0 +1,335 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / common helper functions, etc.
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "common.h"
+
+
+int wpa_debug_level = MSG_INFO;
+int wpa_debug_show_keys = 0;
+int wpa_debug_timestamp = 0;
+
+
+int hostapd_get_rand(u8 *buf, size_t len)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ int i;
+ /* FIX: use more secure pseudo random number generator */
+ for (i = 0; i < len; i++) {
+ buf[i] = rand();
+ }
+ return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "r");
+ if (f == NULL) {
+ printf("Could not open /dev/urandom.\n");
+ return -1;
+ }
+
+ rc = fread(buf, 1, len, f);
+ fclose(f);
+
+ return rc != len ? -1 : 0;
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
+{
+ size_t i;
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ printf("\n");
+}
+
+
+static int hex2num(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+
+static int hex2byte(const char *hex)
+{
+ int a, b;
+ a = hex2num(*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+
+int hwaddr_aton(const char *txt, u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ int a, b;
+
+ a = hex2num(*txt++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*txt++);
+ if (b < 0)
+ return -1;
+ *addr++ = (a << 4) | b;
+ if (i < 5 && *txt++ != ':')
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int hexstr2bin(const char *hex, u8 *buf, size_t len)
+{
+ int i, a;
+ const char *ipos = hex;
+ u8 *opos = buf;
+
+ for (i = 0; i < len; i++) {
+ a = hex2byte(ipos);
+ if (a < 0)
+ return -1;
+ *opos++ = a;
+ ipos += 2;
+ }
+ return 0;
+}
+
+
+char * rel2abs_path(const char *rel_path)
+{
+ char *buf = NULL, *cwd, *ret;
+ size_t len = 128, cwd_len, rel_len, ret_len;
+
+ if (rel_path[0] == '/')
+ return strdup(rel_path);
+
+ for (;;) {
+ buf = malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ free(buf);
+ if (errno != ERANGE) {
+ return NULL;
+ }
+ len *= 2;
+ } else {
+ break;
+ }
+ }
+
+ cwd_len = strlen(cwd);
+ rel_len = strlen(rel_path);
+ ret_len = cwd_len + 1 + rel_len + 1;
+ ret = malloc(ret_len);
+ if (ret) {
+ memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ free(buf);
+ return ret;
+}
+
+
+void inc_byte_array(u8 *counter, size_t len)
+{
+ int pos = len - 1;
+ while (pos >= 0) {
+ counter[pos]++;
+ if (counter[pos] != 0)
+ break;
+ pos--;
+ }
+}
+
+
+void print_char(char c)
+{
+ if (c >= 32 && c < 127)
+ printf("%c", c);
+ else
+ printf("<%02x>", c);
+}
+
+
+void fprint_char(FILE *f, char c)
+{
+ if (c >= 32 && c < 127)
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "<%02x>", c);
+}
+
+
+static void wpa_debug_print_timestamp(void)
+{
+ struct timeval tv;
+ char buf[16];
+
+ if (!wpa_debug_timestamp)
+ return;
+
+ gettimeofday(&tv, NULL);
+ if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
+ localtime((const time_t *) &tv.tv_sec)) <= 0) {
+ snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
+ }
+ printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
+}
+
+
+void wpa_printf(int level, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (level >= wpa_debug_level) {
+ wpa_debug_print_timestamp();
+ vprintf(fmt, ap);
+ printf("\n");
+ }
+ va_end(ap);
+}
+
+
+static void _wpa_hexdump(int level, const char *title, const u8 *buf,
+ size_t len, int show)
+{
+ size_t i;
+ if (level < wpa_debug_level)
+ return;
+ wpa_debug_print_timestamp();
+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+ if (show) {
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ } else {
+ printf(" [REMOVED]");
+ }
+ printf("\n");
+}
+
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
+{
+ _wpa_hexdump(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
+{
+ _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+}
+
+
+static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+ size_t len, int show)
+{
+ int i, llen;
+ const u8 *pos = buf;
+ const int line_len = 16;
+
+ if (level < wpa_debug_level)
+ return;
+ wpa_debug_print_timestamp();
+ if (!show) {
+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ printf(" ");
+ for (i = 0; i < llen; i++)
+ printf(" %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf(" ");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ printf("%c", pos[i]);
+ else
+ printf("_");
+ }
+ for (i = llen; i < line_len; i++)
+ printf(" ");
+ printf("\n");
+ pos += llen;
+ len -= llen;
+ }
+}
+
+
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+{
+ _wpa_hexdump_ascii(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+ size_t len)
+{
+ _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+#define EPOCHFILETIME (116444736000000000ULL)
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ FILETIME ft;
+ LARGE_INTEGER li;
+ ULONGLONG t;
+
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ t = (li.QuadPart - EPOCHFILETIME) / 10;
+ tv->tv_sec = (long) (t / 1000000);
+ tv->tv_usec = (long) (t % 1000000);
+
+ return 0;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/hostapd/common.h b/contrib/hostapd/common.h
new file mode 100644
index 000000000000..aa6429c76b96
--- /dev/null
+++ b/contrib/hostapd/common.h
@@ -0,0 +1,222 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifdef __linux__
+#include <endian.h>
+#include <byteswap.h>
+#endif
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/endian.h>
+#define bswap_16 bswap16
+#define bswap_32 bswap32
+#endif
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#include <winsock2.h>
+
+static inline int daemon(int nochdir, int noclose)
+{
+ printf("Windows - daemon() not supported yet\n");
+ return -1;
+}
+
+static inline void sleep(int seconds)
+{
+ Sleep(seconds * 1000);
+}
+
+static inline void usleep(unsigned long usec)
+{
+ Sleep(usec / 1000);
+}
+
+#ifndef timersub
+#define timersub(a, b, res) do { \
+ (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((res)->tv_usec < 0) { \
+ (res)->tv_sec--; \
+ (res)->tv_usec += 1000000; \
+ } \
+} while (0)
+#endif
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+int gettimeofday(struct timeval *tv, struct timezone *tz);
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+
+static inline unsigned short wpa_swap_16(unsigned short v)
+{
+ return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int wpa_swap_32(unsigned int v)
+{
+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+ ((v & 0xff0000) >> 8) | (v >> 24);
+}
+
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) wpa_swap_16(n)
+#define host_to_be16(n) wpa_swap_16(n)
+#define le_to_host32(n) (n)
+#define be_to_host32(n) wpa_swap_32(n)
+#define host_to_be32(n) wpa_swap_32(n)
+
+#else /* __CYGWIN__ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) bswap_16(n)
+#define host_to_be16(n) bswap_16(n)
+#define le_to_host32(n) (n)
+#define be_to_host32(n) bswap_32(n)
+#define host_to_be32(n) bswap_32(n)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define le_to_host16(n) bswap_16(n)
+#define host_to_le16(n) bswap_16(n)
+#define be_to_host16(n) (n)
+#define host_to_be16(n) (n)
+#define le_to_host32(n) bswap_32(n)
+#define be_to_host32(n) (n)
+#define host_to_be32(n) (n)
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN
+#endif
+#else
+#error Could not determine CPU byte order
+#endif
+
+#endif /* __CYGWIN__ */
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+#include <stdint.h>
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+
+int hostapd_get_rand(u8 *buf, size_t len);
+void hostapd_hexdump(const char *title, const u8 *buf, size_t len);
+int hwaddr_aton(const char *txt, u8 *addr);
+int hexstr2bin(const char *hex, u8 *buf, size_t len);
+char * rel2abs_path(const char *rel_path);
+void inc_byte_array(u8 *counter, size_t len);
+void print_char(char c);
+void fprint_char(FILE *f, char c);
+
+
+/* Debugging function - conditional printf and hex dump. Driver wrappers can
+ * use these for debugging purposes. */
+
+enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
+
+/**
+ * wpa_printf - conditional printf
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_printf(int level, char *fmt, ...)
+__attribute__ ((format (printf, 2, 3)));
+
+/**
+ * wpa_hexdump - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the @buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of @buf is printed out has hex dump.
+ */
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+
+/**
+ * wpa_hexdump_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the @buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of @buf is printed out has hex dump. This works
+ * like wpa_hexdump(), but by default, does not include secret keys (passwords,
+ * etc.) in debug output.
+ */
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+
+/**
+ * wpa_hexdump_ascii - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the @buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of @buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown.
+ */
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+ size_t len);
+
+/**
+ * wpa_hexdump_ascii_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the @buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of @buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
+ * default, does not include secret keys (passwords, etc.) in debug output.
+ */
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+ size_t len);
+
+#ifdef EAPOL_TEST
+#define WPA_ASSERT(a) \
+ do { \
+ if (!(a)) { \
+ printf("WPA_ASSERT FAILED '" #a "' " \
+ "%s %s:%d\n", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ exit(1); \
+ } \
+ } while (0)
+#else
+#define WPA_ASSERT(a) do { } while (0)
+#endif
+
+#endif /* COMMON_H */
diff --git a/contrib/hostapd/config.c b/contrib/hostapd/config.c
new file mode 100644
index 000000000000..ede009aef925
--- /dev/null
+++ b/contrib/hostapd/config.c
@@ -0,0 +1,1136 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / Configuration file
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <grp.h>
+
+#include "hostapd.h"
+#include "driver.h"
+#include "sha1.h"
+#include "eap.h"
+
+
+static struct hostapd_config *hostapd_config_defaults(void)
+{
+ struct hostapd_config *conf;
+
+ conf = malloc(sizeof(*conf));
+ if (conf == NULL) {
+ printf("Failed to allocate memory for configuration data.\n");
+ return NULL;
+ }
+ memset(conf, 0, sizeof(*conf));
+
+ /* set default driver based on configuration */
+ conf->driver = driver_lookup("default");
+ if (conf->driver == NULL) {
+ printf("No default driver registered!\n");
+ free(conf);
+ return NULL;
+ }
+
+ conf->wep_rekeying_period = 300;
+ conf->eap_reauth_period = 3600;
+
+ conf->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+ conf->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+ conf->logger_syslog = (unsigned int) -1;
+ conf->logger_stdout = (unsigned int) -1;
+
+ conf->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
+
+ conf->wpa_group_rekey = 600;
+ conf->wpa_gmk_rekey = 86400;
+ conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ conf->wpa_pairwise = WPA_CIPHER_TKIP;
+ conf->wpa_group = WPA_CIPHER_TKIP;
+
+ conf->radius_server_auth_port = 1812;
+
+ return conf;
+}
+
+
+static int mac_comp(const void *a, const void *b)
+{
+ return memcmp(a, b, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
+ int *num)
+{
+ FILE *f;
+ char buf[128], *pos;
+ int line = 0;
+ u8 addr[ETH_ALEN];
+ macaddr *newacl;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("MAC list file '%s' not found.\n", 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)) {
+ printf("Invalid MAC address '%s' at line %d in '%s'\n",
+ buf, line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ newacl = (macaddr *) realloc(*acl, (*num + 1) * ETH_ALEN);
+ if (newacl == NULL) {
+ printf("MAC list reallocation failed\n");
+ fclose(f);
+ return -1;
+ }
+
+ *acl = newacl;
+ memcpy((*acl)[*num], addr, ETH_ALEN);
+ (*num)++;
+ }
+
+ fclose(f);
+
+ qsort(*acl, *num, sizeof(macaddr), mac_comp);
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wpa_psk(const char *fname,
+ struct hostapd_config *conf)
+{
+ 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) {
+ printf("WPA PSK file '%s' not found.\n", 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)) {
+ printf("Invalid MAC address '%s' on line %d in '%s'\n",
+ buf, line, fname);
+ ret = -1;
+ break;
+ }
+
+ psk = malloc(sizeof(*psk));
+ if (psk == NULL) {
+ printf("WPA PSK allocation failed\n");
+ ret = -1;
+ break;
+ }
+ memset(psk, 0, sizeof(*psk));
+ if (memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ psk->group = 1;
+ else
+ memcpy(psk->addr, addr, ETH_ALEN);
+
+ pos = buf + 17;
+ if (pos == '\0') {
+ printf("No PSK on line %d in '%s'\n", line, fname);
+ free(psk);
+ ret = -1;
+ break;
+ }
+ pos++;
+
+ ok = 0;
+ len = strlen(pos);
+ if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ ok = 1;
+ else if (len >= 8 && len < 64) {
+ pbkdf2_sha1(pos, conf->ssid, conf->ssid_len,
+ 4096, psk->psk, PMK_LEN);
+ ok = 1;
+ }
+ if (!ok) {
+ printf("Invalid PSK '%s' on line %d in '%s'\n",
+ pos, line, fname);
+ free(psk);
+ ret = -1;
+ break;
+ }
+
+ psk->next = conf->wpa_psk;
+ conf->wpa_psk = psk;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
+
+int hostapd_setup_wpa_psk(struct hostapd_config *conf)
+{
+ if (conf->wpa_passphrase != NULL) {
+ if (conf->wpa_psk != NULL) {
+ printf("Warning: both WPA PSK and passphrase set. "
+ "Using passphrase.\n");
+ free(conf->wpa_psk);
+ }
+ conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
+ if (conf->wpa_psk == NULL) {
+ printf("Unable to alloc space for PSK\n");
+ return -1;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "SSID",
+ (u8 *) conf->ssid, conf->ssid_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
+ (u8 *) conf->wpa_passphrase,
+ strlen(conf->wpa_passphrase));
+ memset(conf->wpa_psk, 0, sizeof(struct hostapd_wpa_psk));
+ pbkdf2_sha1(conf->wpa_passphrase,
+ conf->ssid, conf->ssid_len,
+ 4096, conf->wpa_psk->psk, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
+ conf->wpa_psk->psk, PMK_LEN);
+ conf->wpa_psk->group = 1;
+
+ memset(conf->wpa_passphrase, 0, strlen(conf->wpa_passphrase));
+ free(conf->wpa_passphrase);
+ conf->wpa_passphrase = 0;
+ }
+
+ if (conf->wpa_psk_file) {
+ if (hostapd_config_read_wpa_psk(conf->wpa_psk_file, conf))
+ return -1;
+ free(conf->wpa_psk_file);
+ conf->wpa_psk_file = NULL;
+ }
+
+ return 0;
+}
+
+
+#ifdef EAP_AUTHENTICATOR
+static int hostapd_config_read_eap_user(const char *fname,
+ struct hostapd_config *conf)
+{
+ FILE *f;
+ char buf[512], *pos, *start;
+ int line = 0, ret = 0, num_methods;
+ struct hostapd_eap_user *user, *tail = NULL;
+
+ if (!fname)
+ return 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("EAP user file '%s' not found.\n", fname);
+ return -1;
+ }
+
+ /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+ 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;
+
+ user = NULL;
+
+ if (buf[0] != '"' && buf[0] != '*') {
+ printf("Invalid EAP identity (no \" in start) on "
+ "line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user = malloc(sizeof(*user));
+ if (user == NULL) {
+ printf("EAP user allocation failed\n");
+ goto failed;
+ }
+ memset(user, 0, sizeof(*user));
+ user->force_version = -1;
+
+ if (buf[0] == '*') {
+ pos = buf;
+ } else {
+ pos = buf + 1;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ printf("Invalid EAP identity (no \" in end) on"
+ " line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user->identity = malloc(pos - start);
+ if (user->identity == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "identity\n");
+ goto failed;
+ }
+ memcpy(user->identity, start, pos - start);
+ user->identity_len = pos - start;
+ }
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+
+ if (*pos == '\0') {
+ printf("No EAP method on line %d in '%s'\n",
+ line, fname);
+ goto failed;
+ }
+
+ start = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ pos = NULL;
+ } else {
+ *pos = '\0';
+ pos++;
+ }
+ num_methods = 0;
+ while (*start) {
+ char *pos2 = strchr(start, ',');
+ if (pos2) {
+ *pos2++ = '\0';
+ }
+ user->methods[num_methods] = eap_get_type(start);
+ if (user->methods[num_methods] == EAP_TYPE_NONE) {
+ printf("Unsupported EAP type '%s' on line %d "
+ "in '%s'\n", start, line, fname);
+ goto failed;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_USER_MAX_METHODS)
+ break;
+ if (pos2 == NULL)
+ break;
+ start = pos2;
+ }
+ if (num_methods == 0) {
+ printf("No EAP types configured on line %d in '%s'\n",
+ line, fname);
+ goto failed;
+ }
+
+ if (pos == NULL)
+ goto done;
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos == '\0')
+ goto done;
+
+ if (strncmp(pos, "[ver=0]", 7) == 0) {
+ user->force_version = 0;
+ goto done;
+ }
+
+ if (strncmp(pos, "[ver=1]", 7) == 0) {
+ user->force_version = 1;
+ goto done;
+ }
+
+ if (strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ goto done;
+ }
+
+ if (*pos != '"') {
+ printf("Invalid EAP password (no \" in start) on "
+ "line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+ pos++;
+ start = pos;
+ while (*pos != '"' && *pos != '\0')
+ pos++;
+ if (*pos == '\0') {
+ printf("Invalid EAP password (no \" in end) on "
+ "line %d in '%s'\n", line, fname);
+ goto failed;
+ }
+
+ user->password = malloc(pos - start);
+ if (user->password == NULL) {
+ printf("Failed to allocate memory for EAP password\n");
+ goto failed;
+ }
+ memcpy(user->password, start, pos - start);
+ user->password_len = pos - start;
+
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (strncmp(pos, "[2]", 3) == 0) {
+ user->phase2 = 1;
+ }
+
+ done:
+ if (tail == NULL) {
+ tail = conf->eap_user = user;
+ } else {
+ tail->next = user;
+ tail = user;
+ }
+ continue;
+
+ failed:
+ if (user) {
+ free(user->identity);
+ free(user);
+ }
+ ret = -1;
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+#endif /* EAP_AUTHENTICATOR */
+
+
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+ int *num_server, const char *val, int def_port,
+ struct hostapd_radius_server **curr_serv)
+{
+ struct hostapd_radius_server *nserv;
+ int ret;
+ static int server_index = 1;
+
+ nserv = realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ if (nserv == NULL)
+ return -1;
+
+ *server = nserv;
+ nserv = &nserv[*num_server];
+ (*num_server)++;
+ (*curr_serv) = nserv;
+
+ memset(nserv, 0, sizeof(*nserv));
+ nserv->port = def_port;
+ ret = !inet_aton(val, &nserv->addr);
+ nserv->index = server_index++;
+
+ return ret;
+}
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "WPA-PSK") == 0)
+ val |= WPA_KEY_MGMT_PSK;
+ else if (strcmp(start, "WPA-EAP") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X;
+ else {
+ printf("Line %d: invalid key_mgmt '%s'", line, start);
+ free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ free(buf);
+ if (val == 0) {
+ printf("Line %d: no key_mgmt values configured.", line);
+ return -1;
+ }
+
+ return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ printf("Line %d: invalid cipher '%s'.", line, start);
+ free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ printf("Line %d: no cipher values configured.", line);
+ return -1;
+ }
+ return val;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+ if (conf->ieee802_1x && !conf->eap_authenticator &&
+ !conf->auth_servers) {
+ printf("Invalid IEEE 802.1X configuration (no EAP "
+ "authenticator configured).\n");
+ return -1;
+ }
+
+ if (conf->wpa && (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ conf->wpa_psk == NULL && conf->wpa_passphrase == NULL) {
+ printf("WPA-PSK enabled, but PSK or passphrase is not "
+ "configured.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+ struct hostapd_config *conf;
+ FILE *f;
+ char buf[256], *pos;
+ int line = 0;
+ int errors = 0;
+ char *accept_mac_file = NULL, *deny_mac_file = NULL;
+#ifdef EAP_AUTHENTICATOR
+ char *eap_user_file = NULL;
+#endif /* EAP_AUTHENTICATOR */
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ printf("Could not open configuration file '%s' for reading.\n",
+ fname);
+ return NULL;
+ }
+
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ 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;
+
+ pos = strchr(buf, '=');
+ if (pos == NULL) {
+ printf("Line %d: invalid line '%s'\n", line, buf);
+ errors++;
+ continue;
+ }
+ *pos = '\0';
+ pos++;
+
+ if (strcmp(buf, "interface") == 0) {
+ snprintf(conf->iface, sizeof(conf->iface), "%s", pos);
+ } else if (strcmp(buf, "bridge") == 0) {
+ snprintf(conf->bridge, sizeof(conf->bridge), "%s",
+ pos);
+ } else if (strcmp(buf, "driver") == 0) {
+ conf->driver = driver_lookup(pos);
+ if (conf->driver == NULL) {
+ printf("Line %d: invalid/unknown driver "
+ "'%s'\n", line, pos);
+ errors++;
+ }
+ } else if (strcmp(buf, "debug") == 0) {
+ conf->debug = atoi(pos);
+ } else if (strcmp(buf, "logger_syslog_level") == 0) {
+ conf->logger_syslog_level = atoi(pos);
+ } else if (strcmp(buf, "logger_stdout_level") == 0) {
+ conf->logger_stdout_level = atoi(pos);
+ } else if (strcmp(buf, "logger_syslog") == 0) {
+ conf->logger_syslog = atoi(pos);
+ } else if (strcmp(buf, "logger_stdout") == 0) {
+ conf->logger_stdout = atoi(pos);
+ } else if (strcmp(buf, "dump_file") == 0) {
+ conf->dump_log_name = strdup(pos);
+ } else if (strcmp(buf, "ssid") == 0) {
+ conf->ssid_len = strlen(pos);
+ if (conf->ssid_len >= HOSTAPD_SSID_LEN ||
+ conf->ssid_len < 1) {
+ printf("Line %d: invalid SSID '%s'\n", line,
+ pos);
+ errors++;
+ }
+ memcpy(conf->ssid, pos, conf->ssid_len);
+ conf->ssid[conf->ssid_len] = '\0';
+ conf->ssid_set = 1;
+ } else if (strcmp(buf, "macaddr_acl") == 0) {
+ conf->macaddr_acl = atoi(pos);
+ if (conf->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+ conf->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+ conf->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ printf("Line %d: unknown macaddr_acl %d\n",
+ line, conf->macaddr_acl);
+ }
+ } else if (strcmp(buf, "accept_mac_file") == 0) {
+ accept_mac_file = strdup(pos);
+ if (!accept_mac_file) {
+ printf("Line %d: allocation failed\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "deny_mac_file") == 0) {
+ deny_mac_file = strdup(pos);
+ if (!deny_mac_file) {
+ printf("Line %d: allocation failed\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "assoc_ap_addr") == 0) {
+ if (hwaddr_aton(pos, conf->assoc_ap_addr)) {
+ printf("Line %d: invalid MAC address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ conf->assoc_ap = 1;
+ } else if (strcmp(buf, "ieee8021x") == 0) {
+ conf->ieee802_1x = atoi(pos);
+#ifdef EAP_AUTHENTICATOR
+ } else if (strcmp(buf, "eap_authenticator") == 0) {
+ conf->eap_authenticator = atoi(pos);
+ } else if (strcmp(buf, "eap_user_file") == 0) {
+ free(eap_user_file);
+ eap_user_file = strdup(pos);
+ if (!eap_user_file) {
+ printf("Line %d: allocation failed\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "ca_cert") == 0) {
+ free(conf->ca_cert);
+ conf->ca_cert = strdup(pos);
+ } else if (strcmp(buf, "server_cert") == 0) {
+ free(conf->server_cert);
+ conf->server_cert = strdup(pos);
+ } else if (strcmp(buf, "private_key") == 0) {
+ free(conf->private_key);
+ conf->private_key = strdup(pos);
+ } else if (strcmp(buf, "private_key_passwd") == 0) {
+ free(conf->private_key_passwd);
+ conf->private_key_passwd = strdup(pos);
+#ifdef EAP_SIM
+ } else if (strcmp(buf, "eap_sim_db") == 0) {
+ free(conf->eap_sim_db);
+ conf->eap_sim_db = strdup(pos);
+#endif /* EAP_SIM */
+#endif /* EAP_AUTHENTICATOR */
+ } else if (strcmp(buf, "eap_message") == 0) {
+ conf->eap_req_id_text = strdup(pos);
+ } else if (strcmp(buf, "wep_key_len_broadcast") == 0) {
+ conf->default_wep_key_len = atoi(pos);
+ if (conf->default_wep_key_len > 13) {
+ printf("Line %d: invalid WEP key len %lu "
+ "(= %lu bits)\n", line,
+ (unsigned long)
+ conf->default_wep_key_len,
+ (unsigned long)
+ conf->default_wep_key_len * 8);
+ errors++;
+ }
+ } else if (strcmp(buf, "wep_key_len_unicast") == 0) {
+ conf->individual_wep_key_len = atoi(pos);
+ if (conf->individual_wep_key_len < 0 ||
+ conf->individual_wep_key_len > 13) {
+ printf("Line %d: invalid WEP key len %d "
+ "(= %d bits)\n", line,
+ conf->individual_wep_key_len,
+ conf->individual_wep_key_len * 8);
+ errors++;
+ }
+ } else if (strcmp(buf, "wep_rekey_period") == 0) {
+ conf->wep_rekeying_period = atoi(pos);
+ if (conf->wep_rekeying_period < 0) {
+ printf("Line %d: invalid period %d\n",
+ line, conf->wep_rekeying_period);
+ errors++;
+ }
+ } else if (strcmp(buf, "eap_reauth_period") == 0) {
+ conf->eap_reauth_period = atoi(pos);
+ if (conf->eap_reauth_period < 0) {
+ printf("Line %d: invalid period %d\n",
+ line, conf->eap_reauth_period);
+ errors++;
+ }
+ } else if (strcmp(buf, "eapol_key_index_workaround") == 0) {
+ conf->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+ } else if (strcmp(buf, "iapp_interface") == 0) {
+ conf->ieee802_11f = 1;
+ snprintf(conf->iapp_iface, sizeof(conf->iapp_iface),
+ "%s", pos);
+#endif /* CONFIG_IAPP */
+ } else if (strcmp(buf, "own_ip_addr") == 0) {
+ if (!inet_aton(pos, &conf->own_ip_addr)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (strcmp(buf, "nas_identifier") == 0) {
+ conf->nas_identifier = strdup(pos);
+ } else if (strcmp(buf, "auth_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &conf->auth_servers,
+ &conf->num_auth_servers, pos, 1812,
+ &conf->auth_server)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (conf->auth_server &&
+ strcmp(buf, "auth_server_port") == 0) {
+ conf->auth_server->port = atoi(pos);
+ } else if (conf->auth_server &&
+ strcmp(buf, "auth_server_shared_secret") == 0) {
+ int len = strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ printf("Line %d: empty shared secret is not "
+ "allowed.\n", line);
+ errors++;
+ }
+ conf->auth_server->shared_secret = (u8 *) strdup(pos);
+ conf->auth_server->shared_secret_len = len;
+ } else if (strcmp(buf, "acct_server_addr") == 0) {
+ if (hostapd_config_read_radius_addr(
+ &conf->acct_servers,
+ &conf->num_acct_servers, pos, 1813,
+ &conf->acct_server)) {
+ printf("Line %d: invalid IP address '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (conf->acct_server &&
+ strcmp(buf, "acct_server_port") == 0) {
+ conf->acct_server->port = atoi(pos);
+ } else if (conf->acct_server &&
+ strcmp(buf, "acct_server_shared_secret") == 0) {
+ int len = strlen(pos);
+ if (len == 0) {
+ /* RFC 2865, Ch. 3 */
+ printf("Line %d: empty shared secret is not "
+ "allowed.\n", line);
+ errors++;
+ }
+ conf->acct_server->shared_secret = (u8 *) strdup(pos);
+ conf->acct_server->shared_secret_len = len;
+ } else if (strcmp(buf, "radius_retry_primary_interval") == 0) {
+ conf->radius_retry_primary_interval = atoi(pos);
+ } else if (strcmp(buf, "radius_acct_interim_interval") == 0) {
+ conf->radius_acct_interim_interval = atoi(pos);
+ } else if (strcmp(buf, "auth_algs") == 0) {
+ conf->auth_algs = atoi(pos);
+ if (conf->auth_algs == 0) {
+ printf("Line %d: no authentication algorithms "
+ "allowed\n",
+ line);
+ errors++;
+ }
+ } else if (strcmp(buf, "wpa") == 0) {
+ conf->wpa = atoi(pos);
+ } else if (strcmp(buf, "wpa_group_rekey") == 0) {
+ conf->wpa_group_rekey = atoi(pos);
+ } else if (strcmp(buf, "wpa_strict_rekey") == 0) {
+ conf->wpa_strict_rekey = atoi(pos);
+ } else if (strcmp(buf, "wpa_gmk_rekey") == 0) {
+ conf->wpa_gmk_rekey = atoi(pos);
+ } else if (strcmp(buf, "wpa_passphrase") == 0) {
+ int len = strlen(pos);
+ if (len < 8 || len > 63) {
+ printf("Line %d: invalid WPA passphrase length"
+ " %d (expected 8..63)\n", line, len);
+ errors++;
+ } else {
+ free(conf->wpa_passphrase);
+ conf->wpa_passphrase = strdup(pos);
+ }
+ } else if (strcmp(buf, "wpa_psk") == 0) {
+ free(conf->wpa_psk);
+ conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
+ if (conf->wpa_psk) {
+ memset(conf->wpa_psk, 0,
+ sizeof(struct hostapd_wpa_psk));
+ }
+ if (conf->wpa_psk == NULL)
+ errors++;
+ else if (hexstr2bin(pos, conf->wpa_psk->psk, PMK_LEN)
+ || pos[PMK_LEN * 2] != '\0') {
+ printf("Line %d: Invalid PSK '%s'.\n", line,
+ pos);
+ errors++;
+ } else {
+ conf->wpa_psk->group = 1;
+ }
+ } else if (strcmp(buf, "wpa_psk_file") == 0) {
+ free(conf->wpa_psk_file);
+ conf->wpa_psk_file = strdup(pos);
+ if (!conf->wpa_psk_file) {
+ printf("Line %d: allocation failed\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "wpa_key_mgmt") == 0) {
+ conf->wpa_key_mgmt =
+ hostapd_config_parse_key_mgmt(line, pos);
+ if (conf->wpa_key_mgmt == -1)
+ errors++;
+ } else if (strcmp(buf, "wpa_pairwise") == 0) {
+ conf->wpa_pairwise =
+ hostapd_config_parse_cipher(line, pos);
+ if (conf->wpa_pairwise == -1 ||
+ conf->wpa_pairwise == 0)
+ errors++;
+ else if (conf->wpa_pairwise &
+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104)) {
+ printf("Line %d: unsupported pairwise "
+ "cipher suite '%s'\n",
+ conf->wpa_pairwise, pos);
+ errors++;
+ } else {
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ conf->wpa_group = WPA_CIPHER_TKIP;
+ else
+ conf->wpa_group = WPA_CIPHER_CCMP;
+ }
+#ifdef CONFIG_RSN_PREAUTH
+ } else if (strcmp(buf, "rsn_preauth") == 0) {
+ conf->rsn_preauth = atoi(pos);
+ } else if (strcmp(buf, "rsn_preauth_interfaces") == 0) {
+ conf->rsn_preauth_interfaces = strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+ } else if (strcmp(buf, "ctrl_interface") == 0) {
+ free(conf->ctrl_interface);
+ conf->ctrl_interface = strdup(pos);
+ } else if (strcmp(buf, "ctrl_interface_group") == 0) {
+ struct group *grp;
+ char *endp;
+ const char *group = pos;
+
+ grp = getgrnam(group);
+ if (grp) {
+ conf->ctrl_interface_gid = grp->gr_gid;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ conf->ctrl_interface_gid, group);
+ continue;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ conf->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+ "'%s'", line, group);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ conf->ctrl_interface_gid);
+#ifdef RADIUS_SERVER
+ } else if (strcmp(buf, "radius_server_clients") == 0) {
+ free(conf->radius_server_clients);
+ conf->radius_server_clients = strdup(pos);
+ } else if (strcmp(buf, "radius_server_auth_port") == 0) {
+ conf->radius_server_auth_port = atoi(pos);
+#endif /* RADIUS_SERVER */
+ } else {
+ printf("Line %d: unknown configuration item '%s'\n",
+ line, buf);
+ errors++;
+ }
+ }
+
+ fclose(f);
+
+ if (hostapd_config_read_maclist(accept_mac_file, &conf->accept_mac,
+ &conf->num_accept_mac))
+ errors++;
+ free(accept_mac_file);
+ if (hostapd_config_read_maclist(deny_mac_file, &conf->deny_mac,
+ &conf->num_deny_mac))
+ errors++;
+ free(deny_mac_file);
+
+#ifdef EAP_AUTHENTICATOR
+ if (hostapd_config_read_eap_user(eap_user_file, conf))
+ errors++;
+ free(eap_user_file);
+#endif /* EAP_AUTHENTICATOR */
+
+ conf->auth_server = conf->auth_servers;
+ conf->acct_server = conf->acct_servers;
+
+ if (hostapd_config_check(conf))
+ errors++;
+
+ if (errors) {
+ printf("%d errors found in configuration file '%s'\n",
+ errors, fname);
+ hostapd_config_free(conf);
+ conf = NULL;
+ }
+
+ return conf;
+}
+
+
+static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
+ int num_servers)
+{
+ int i;
+
+ for (i = 0; i < num_servers; i++) {
+ free(servers[i].shared_secret);
+ }
+ free(servers);
+}
+
+
+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+{
+ free(user->identity);
+ free(user->password);
+ free(user);
+}
+
+
+void hostapd_config_free(struct hostapd_config *conf)
+{
+ struct hostapd_wpa_psk *psk, *prev;
+ struct hostapd_eap_user *user, *prev_user;
+
+ if (conf == NULL)
+ return;
+
+ psk = conf->wpa_psk;
+ while (psk) {
+ prev = psk;
+ psk = psk->next;
+ free(prev);
+ }
+
+ free(conf->wpa_passphrase);
+ free(conf->wpa_psk_file);
+
+ user = conf->eap_user;
+ while (user) {
+ prev_user = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev_user);
+ }
+
+ free(conf->dump_log_name);
+ free(conf->eap_req_id_text);
+ free(conf->accept_mac);
+ free(conf->deny_mac);
+ free(conf->nas_identifier);
+ hostapd_config_free_radius(conf->auth_servers, conf->num_auth_servers);
+ hostapd_config_free_radius(conf->acct_servers, conf->num_acct_servers);
+ free(conf->rsn_preauth_interfaces);
+ free(conf->ctrl_interface);
+ free(conf->ca_cert);
+ free(conf->server_cert);
+ free(conf->private_key);
+ free(conf->private_key_passwd);
+ free(conf->eap_sim_db);
+ free(conf->radius_server_clients);
+ free(conf);
+}
+
+
+/* Perform a binary search for given MAC address from a pre-sorted list.
+ * Returns 1 if address is in the list or 0 if not. */
+int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr)
+{
+ int start, end, middle, res;
+
+ start = 0;
+ end = num_entries - 1;
+
+ while (start <= end) {
+ middle = (start + end) / 2;
+ res = memcmp(list[middle], addr, ETH_ALEN);
+ if (res == 0)
+ return 1;
+ if (res < 0)
+ start = middle + 1;
+ else
+ end = middle - 1;
+ }
+
+ return 0;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
+ const u8 *prev_psk)
+{
+ struct hostapd_wpa_psk *psk;
+ int next_ok = prev_psk == NULL;
+
+ for (psk = conf->wpa_psk; psk != NULL; psk = psk->next) {
+ if (next_ok &&
+ (psk->group || 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_config *conf, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ struct hostapd_eap_user *user = conf->eap_user;
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+ return user;
+}
diff --git a/contrib/hostapd/config.h b/contrib/hostapd/config.h
new file mode 100644
index 000000000000..0ffc3adb4366
--- /dev/null
+++ b/contrib/hostapd/config.h
@@ -0,0 +1,177 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct hostapd_radius_server {
+ /* MIB prefix for shared variables:
+ * @ = radiusAuth or radiusAcc depending on the type of the server */
+ struct in_addr addr; /* @ServerAddress */
+ int port; /* @ClientServerPortNumber */
+ u8 *shared_secret;
+ size_t shared_secret_len;
+
+ /* Dynamic (not from configuration file) MIB data */
+ int index; /* @ServerIndex */
+ int round_trip_time; /* @ClientRoundTripTime; in hundredths of a
+ * second */
+ u32 requests; /* @Client{Access,}Requests */
+ u32 retransmissions; /* @Client{Access,}Retransmissions */
+ u32 access_accepts; /* radiusAuthClientAccessAccepts */
+ u32 access_rejects; /* radiusAuthClientAccessRejects */
+ u32 access_challenges; /* radiusAuthClientAccessChallenges */
+ u32 responses; /* radiusAccClientResponses */
+ u32 malformed_responses; /* @ClientMalformed{Access,}Responses */
+ u32 bad_authenticators; /* @ClientBadAuthenticators */
+ u32 timeouts; /* @ClientTimeouts */
+ u32 unknown_types; /* @ClientUnknownTypes */
+ u32 packets_dropped; /* @ClientPacketsDropped */
+ /* @ClientPendingRequests: length of hapd->radius->msgs for matching
+ * msg_type */
+};
+
+#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;
+ u8 methods[EAP_USER_MAX_METHODS];
+ u8 *password;
+ size_t password_len;
+ int phase2;
+ int force_version;
+};
+
+struct hostapd_config {
+ char iface[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
+
+ const struct driver_ops *driver;
+
+ enum {
+ HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
+ HOSTAPD_LEVEL_DEBUG = 1,
+ HOSTAPD_LEVEL_INFO = 2,
+ HOSTAPD_LEVEL_NOTICE = 3,
+ HOSTAPD_LEVEL_WARNING = 4
+ } logger_syslog_level, logger_stdout_level;
+
+#define HOSTAPD_MODULE_IEEE80211 BIT(0)
+#define HOSTAPD_MODULE_IEEE8021X BIT(1)
+#define HOSTAPD_MODULE_RADIUS BIT(2)
+#define HOSTAPD_MODULE_WPA BIT(3)
+#define HOSTAPD_MODULE_DRIVER BIT(4)
+#define HOSTAPD_MODULE_IAPP BIT(5)
+ unsigned int logger_syslog; /* module bitfield */
+ unsigned int logger_stdout; /* module bitfield */
+
+ enum { HOSTAPD_DEBUG_NO = 0, HOSTAPD_DEBUG_MINIMAL = 1,
+ HOSTAPD_DEBUG_VERBOSE = 2,
+ HOSTAPD_DEBUG_MSGDUMPS = 3,
+ HOSTAPD_DEBUG_EXCESSIVE = 4 } debug; /* debug verbosity level */
+ char *dump_log_name; /* file name for state dump (SIGUSR1) */
+
+ int ieee802_1x; /* use IEEE 802.1X */
+ int eap_authenticator; /* Use internal EAP authenticator instead of
+ * external RADIUS server */
+ struct hostapd_eap_user *eap_user;
+ char *eap_sim_db;
+ struct in_addr own_ip_addr;
+ char *nas_identifier;
+ /* RADIUS Authentication and Accounting servers in priority order */
+ struct hostapd_radius_server *auth_servers, *auth_server;
+ int num_auth_servers;
+ struct hostapd_radius_server *acct_servers, *acct_server;
+ int num_acct_servers;
+
+ int radius_retry_primary_interval;
+ int radius_acct_interim_interval;
+#define HOSTAPD_SSID_LEN 32
+ char ssid[HOSTAPD_SSID_LEN + 1];
+ size_t ssid_len;
+ int ssid_set;
+ char *eap_req_id_text; /* optional displayable message sent with
+ * EAP Request-Identity */
+ int eapol_key_index_workaround;
+
+ size_t default_wep_key_len;
+ int individual_wep_key_len;
+ int wep_rekeying_period;
+ int eap_reauth_period;
+
+ int ieee802_11f; /* use IEEE 802.11f (IAPP) */
+ char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
+ * frames */
+
+ u8 assoc_ap_addr[ETH_ALEN];
+ int assoc_ap; /* whether assoc_ap_addr is set */
+
+ enum {
+ ACCEPT_UNLESS_DENIED = 0,
+ DENY_UNLESS_ACCEPTED = 1,
+ USE_EXTERNAL_RADIUS_AUTH = 2
+ } macaddr_acl;
+ macaddr *accept_mac;
+ int num_accept_mac;
+ macaddr *deny_mac;
+ int num_deny_mac;
+
+#define HOSTAPD_AUTH_OPEN BIT(0)
+#define HOSTAPD_AUTH_SHARED_KEY BIT(1)
+ int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
+ * algorithms */
+
+#define HOSTAPD_WPA_VERSION_WPA BIT(0)
+#define HOSTAPD_WPA_VERSION_WPA2 BIT(1)
+ int wpa;
+ struct hostapd_wpa_psk *wpa_psk;
+ char *wpa_passphrase;
+ char *wpa_psk_file;
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+ int wpa_key_mgmt;
+#define WPA_CIPHER_NONE BIT(0)
+#define WPA_CIPHER_WEP40 BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP BIT(3)
+#define WPA_CIPHER_CCMP BIT(4)
+ int wpa_pairwise;
+ int wpa_group;
+ int wpa_group_rekey;
+ int wpa_strict_rekey;
+ int wpa_gmk_rekey;
+ int rsn_preauth;
+ char *rsn_preauth_interfaces;
+
+ char *ctrl_interface; /* directory for UNIX domain sockets */
+ gid_t ctrl_interface_gid;
+
+ char *ca_cert;
+ char *server_cert;
+ char *private_key;
+ char *private_key_passwd;
+
+ char *radius_server_clients;
+ int radius_server_auth_port;
+};
+
+
+struct hostapd_config * hostapd_config_read(const char *fname);
+void hostapd_config_free(struct hostapd_config *conf);
+int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr);
+const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
+ const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_config *conf);
+const struct hostapd_eap_user *
+hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
+ size_t identity_len, int phase2);
+
+#endif /* CONFIG_H */
diff --git a/contrib/hostapd/crypto.c b/contrib/hostapd/crypto.c
new file mode 100644
index 000000000000..cd278e0fae59
--- /dev/null
+++ b/contrib/hostapd/crypto.c
@@ -0,0 +1,71 @@
+/*
+ * WPA Supplicant / wrapper functions for libcrypto
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <openssl/md4.h>
+#include <openssl/des.h>
+
+#include "common.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 */
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
+{
+ MD4_CTX ctx;
+ int i;
+
+ MD4_Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ MD4_Update(&ctx, addr[i], len[i]);
+ MD4_Final(mac, &ctx);
+}
+
+
+void md4(const u8 *addr, size_t len, u8 *mac)
+{
+ md4_vector(1, &addr, &len, mac);
+}
+
+
+/**
+ * @clear: 8 octets (in)
+ * @key: 7 octets (in) (no parity bits included)
+ * @cypher: 8 octets (out)
+ */
+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);
+}
diff --git a/contrib/hostapd/crypto.h b/contrib/hostapd/crypto.h
new file mode 100644
index 000000000000..3e1a0e5cd3f8
--- /dev/null
+++ b/contrib/hostapd/crypto.h
@@ -0,0 +1,8 @@
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+void md4(const u8 *addr, size_t len, u8 *mac);
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+
+#endif /* CRYPTO_H */
diff --git a/contrib/hostapd/ctrl_iface.c b/contrib/hostapd/ctrl_iface.c
new file mode 100644
index 000000000000..8cf356cb460f
--- /dev/null
+++ b/contrib/hostapd/ctrl_iface.c
@@ -0,0 +1,452 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "ieee802_1x.h"
+#include "wpa.h"
+#include "radius_client.h"
+#include "ieee802_11.h"
+#include "ctrl_iface.h"
+#include "sta_info.h"
+
+
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = malloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ memset(dst, 0, sizeof(*dst));
+ memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = hapd->ctrl_dst;
+ hapd->ctrl_dst = dst;
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+ (u8 *) from->sun_path, fromlen);
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
+ if (prev == NULL)
+ hapd->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ free(dst);
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ (u8 *) from->sun_path, fromlen);
+ return 0;
+ }
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
+ struct sockaddr_un *from,
+ socklen_t fromlen,
+ char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level", (u8 *) from->sun_path, fromlen);
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ dst = dst->next;
+ }
+
+ return -1;
+}
+
+
+static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ int len, res;
+
+ if (sta == NULL) {
+ return snprintf(buf, buflen, "FAIL\n");
+ }
+
+ len = 0;
+ len += snprintf(buf + len, buflen - len, MACSTR "\n",
+ MAC2STR(sta->addr));
+
+ res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+ res = wpa_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+ res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
+ return len;
+}
+
+
+static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
+}
+
+
+static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(txtaddr, addr))
+ return snprintf(buf, buflen, "FAIL\n");
+ return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
+ buf, buflen);
+}
+
+
+static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ if (hwaddr_aton(txtaddr, addr) ||
+ (sta = ap_get_sta(hapd, addr)) == NULL)
+ return snprintf(buf, buflen, "FAIL\n");
+ return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ const int reply_size = 4096;
+ int reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+ wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
+
+ reply = malloc(reply_size);
+ if (reply == NULL) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ return;
+ }
+
+ memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (strcmp(buf, "PING") == 0) {
+ memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (strcmp(buf, "MIB") == 0) {
+ reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+ if (reply_len >= 0) {
+ res = wpa_get_mib(hapd, reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ if (reply_len >= 0) {
+ res = ieee802_1x_get_mib(hapd, reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ if (reply_len >= 0) {
+ res = radius_client_get_mib(hapd->radius,
+ reply + reply_len,
+ reply_size - reply_len);
+ if (res < 0)
+ reply_len = -1;
+ else
+ reply_len += res;
+ }
+ } else if (strcmp(buf, "STA-FIRST") == 0) {
+ reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+ reply_size);
+ } else if (strncmp(buf, "STA ", 4) == 0) {
+ reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
+ reply_size);
+ } else if (strncmp(buf, "STA-NEXT ", 9) == 0) {
+ reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+ reply_size);
+ } else if (strcmp(buf, "ATTACH") == 0) {
+ if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+ reply_len = -1;
+ } else if (strcmp(buf, "DETACH") == 0) {
+ if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+ reply_len = -1;
+ } else if (strncmp(buf, "LEVEL ", 6) == 0) {
+ if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+ buf + 6))
+ reply_len = -1;
+ } else {
+ memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+ }
+
+ if (reply_len < 0) {
+ memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ free(reply);
+}
+
+
+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
+{
+ char *buf;
+ size_t len;
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return NULL;
+
+ len = strlen(hapd->conf->ctrl_interface) + strlen(hapd->conf->iface) +
+ 2;
+ buf = malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ snprintf(buf, len, "%s/%s",
+ hapd->conf->ctrl_interface, hapd->conf->iface);
+ return buf;
+}
+
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ hapd->ctrl_sock = -1;
+
+ if (hapd->conf->ctrl_interface == NULL)
+ return 0;
+
+ if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (chown(hapd->conf->ctrl_interface, 0,
+ hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface]");
+ return -1;
+ }
+
+ if (strlen(hapd->conf->ctrl_interface) + 1 + strlen(hapd->conf->iface)
+ >= sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ fname = hostapd_ctrl_iface_path(hapd);
+ if (fname == NULL)
+ goto fail;
+ strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+
+ if (chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ goto fail;
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ free(fname);
+
+ hapd->ctrl_sock = s;
+ eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+ NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ free(fname);
+ }
+ return -1;
+}
+
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (hapd->ctrl_sock > -1) {
+ char *fname;
+ eloop_unregister_read_sock(hapd->ctrl_sock);
+ close(hapd->ctrl_sock);
+ hapd->ctrl_sock = -1;
+ fname = hostapd_ctrl_iface_path(hapd);
+ if (fname)
+ unlink(fname);
+ free(fname);
+
+ if (rmdir(hapd->conf->ctrl_interface) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ }
+
+ dst = hapd->ctrl_dst;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ free(prev);
+ }
+}
+
+
+void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ char *buf, size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ struct msghdr msg;
+ int idx;
+ struct iovec io[2];
+ char levelstr[10];
+
+ dst = hapd->ctrl_dst;
+ if (hapd->ctrl_sock < 0 || dst == NULL)
+ return;
+
+ snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ io[0].iov_base = levelstr;
+ io[0].iov_len = strlen(levelstr);
+ io[1].iov_base = buf;
+ io[1].iov_len = len;
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+ (u8 *) dst->addr.sun_path, dst->addrlen);
+ msg.msg_name = &dst->addr;
+ msg.msg_namelen = dst->addrlen;
+ if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+ fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
+ idx);
+ perror("sendmsg");
+ dst->errors++;
+ if (dst->errors > 10) {
+ hostapd_ctrl_iface_detach(
+ hapd, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+}
diff --git a/contrib/hostapd/ctrl_iface.h b/contrib/hostapd/ctrl_iface.h
new file mode 100644
index 000000000000..ef1a541c94c8
--- /dev/null
+++ b/contrib/hostapd/ctrl_iface.h
@@ -0,0 +1,9 @@
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ char *buf, size_t len);
+
+#endif /* CTRL_IFACE_H */
diff --git a/contrib/hostapd/defconfig b/contrib/hostapd/defconfig
new file mode 100644
index 000000000000..b27c0374da5e
--- /dev/null
+++ b/contrib/hostapd/defconfig
@@ -0,0 +1,66 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../head # change to reflect local setup; directory for madwifi src
+
+# Driver interface for Prism54 driver
+#CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# Integrated EAP authenticator
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP authenticator
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP authenticator
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP authenticator
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP authenticator
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP authenticator
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP authenticator
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP authenticator
+#CONFIG_EAP_SIM=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# authenticator from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
diff --git a/contrib/hostapd/defs.h b/contrib/hostapd/defs.h
new file mode 100644
index 000000000000..a5a515c552f5
--- /dev/null
+++ b/contrib/hostapd/defs.h
@@ -0,0 +1,14 @@
+#ifndef DEFS_H
+#define DEFS_H
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+#endif /* CONFIG_NATIVE_WINDOWS */
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+#endif /* DEFS_H */
diff --git a/contrib/hostapd/developer.txt b/contrib/hostapd/developer.txt
new file mode 100644
index 000000000000..e1d316341390
--- /dev/null
+++ b/contrib/hostapd/developer.txt
@@ -0,0 +1,219 @@
+Developer notes for hostapd
+===========================
+
+hostapd daemon setup, operations, and shutdown
+----------------------------------------------
+
+Files: hostapd.[ch]
+
+Externally called functions:
+ hostapd_new_assoc_sta() is called when a station associates with the AP
+
+Event loop functions:
+ handle_term() is called on SIGINT and SIGTERM to terminate hostapd process
+ handle_reload() is called on SIGHUP to reload configuration
+ handle_dump_state() is called on SIGUSR1 to dump station state data to a
+ text file
+ hostapd_rotate_wep() is called to periodically change WEP keys
+
+
+Configuration parsing
+---------------------
+
+Configuration file parsing and data structure definition.
+
+Files: config.[ch]
+
+Externally called functions:
+ hostapd_config_read() is called to read and parse a configuration file;
+ allocates and returns configuration data structure
+ hostapd_config_free() is called to free configuration data structure
+ hostapd_maclist_found() is called to check whether a given address is found
+ in a list of MAC addresses
+
+
+Kernel driver access
+--------------------
+
+Helper functions for configuring the Host AP kernel driver and
+accessing data from it.
+
+Files: driver.[ch]
+
+
+IEEE 802.11 frame handling (netdevice wlan#ap)
+----------------------------------------------
+
+Receive all incoming IEEE 802.11 frames from the kernel driver via
+wlan#ap interface.
+
+Files: receive.c
+
+Externally called functions:
+ hostapd_init_sockets() is called to initialize sockets for receiving and
+ sending IEEE 802.11 frames via wlan#ap interface
+
+Event loop functions:
+ handle_read() is called for each incoming packet from wlan#ap net device
+
+
+Station table
+-------------
+
+Files: sta_info.[ch], ap.h
+
+Event loop functions:
+ ap_handle_timer() is called to check station activity and to remove
+ inactive stations
+
+
+IEEE 802.11 management
+----------------------
+
+IEEE 802.11 management frame sending and processing (mainly,
+authentication and association). IEEE 802.11 station functionality
+(authenticate and associate with another AP as an station).
+
+Files: ieee802_11.[ch]
+
+Externally called functions:
+ ieee802_11_mgmt() is called for each received IEEE 802.11 management frame
+ (from handle_frame() in hostapd.c)
+ ieee802_11_mgmt_cb() is called for each received TX callback of IEEE 802.11
+ management frame (from handle_tx_callback() in hostapd.c)
+ ieee802_11_send_deauth() is called to send deauthentication frame
+ ieee802_11_send_disassoc() is called to send disassociation frame
+ ieee802_11_parse_elems() is used to parse information elements in
+ IEEE 802.11 management frames
+
+Event loop functions:
+ ieee802_11_sta_authenticate() called to retry authentication (with another
+ AP)
+ ieee802_11_sta_associate() called to retry association (with another AP)
+
+
+IEEE 802.11 authentication
+--------------------------
+
+Access control list for IEEE 802.11 authentication. Uses staticly
+configured ACL from configuration files or an external RADIUS
+server. Results from external RADIUS queries are cached to allow
+faster authentication frame processing.
+
+Files: ieee802_11_auth.[ch]
+
+Externally called functions:
+ hostapd_acl_init() called once during hostapd startup
+ hostapd_acl_deinit() called once during hostapd shutdown
+ hostapd_acl_recv_radius() called by IEEE 802.1X code for incoming RADIUS
+ Authentication messages (returns 0 if message was processed)
+ hostapd_allowed_address() called to check whether a specified station can be
+ authenticated
+
+Event loop functions:
+ hostapd_acl_expire() is called to expire ACL cache entries
+
+
+IEEE 802.1X Authenticator
+-------------------------
+
+Files: ieee802_1x.[ch]
+
+
+Externally called functions:
+ ieee802_1x_receive() is called for each incoming EAPOL frame from the
+ wireless interface
+ ieee802_1x_new_station() is called to start IEEE 802.1X authentication when
+ a new station completes IEEE 802.11 association
+
+Event loop functions:
+ ieee802_1x_receive_auth() called for each incoming RADIUS Authentication
+ message
+
+
+EAPOL state machine
+-------------------
+
+IEEE 802.1X state machine for EAPOL.
+
+Files: eapol_sm.[ch]
+
+Externally called functions:
+ eapol_sm_step() is called to advance EAPOL state machines after any change
+ that could affect their state
+
+Event loop functions:
+ eapol_port_timers_tick() called once per second to advance Port Timers state
+ machine
+
+
+IEEE 802.11f (IAPP)
+-------------------
+
+Files: iapp.[ch]
+
+Externally called functions:
+ iapp_new_station() is called to start accounting session when a new station
+ completes IEEE 802.11 association or IEEE 802.1X authentication
+
+Event loop functions:
+ iapp_receive_udp() is called for incoming IAPP frames over UDP
+
+
+Per station accounting
+----------------------
+
+Send RADIUS Accounting start and stop messages to a RADIUS Accounting
+server. Process incoming RADIUS Accounting messages.
+
+Files: accounting.[ch]
+
+Externally called functions:
+ accounting_init() called once during hostapd startup
+ accounting_deinit() called once during hostapd shutdown
+ accounting_sta_start() called when a station starts new session
+ accounting_sta_stop() called when a station session is terminated
+
+Event loop functions:
+ accounting_receive() called for each incoming RADIUS Accounting message
+ accounting_list_timer() called to retransmit accounting messages and to
+ remove expired entries
+
+
+RADIUS messages
+---------------
+
+RADIUS message generation and parsing functions.
+
+Files: radius.[ch]
+
+
+Event loop
+----------
+
+Event loop for registering timeout calls, signal handlers, and socket
+read events.
+
+Files: eloop.[ch]
+
+
+RC4
+---
+
+RC4 encryption
+
+Files: rc4.[ch]
+
+
+MD5
+---
+
+MD5 hash and HMAC-MD5.
+
+Files: md5.[ch]
+
+
+Miscellaneous helper functions
+------------------------------
+
+Files: common.[ch]
diff --git a/contrib/hostapd/driver.h b/contrib/hostapd/driver.h
new file mode 100644
index 000000000000..365deda48a2a
--- /dev/null
+++ b/contrib/hostapd/driver.h
@@ -0,0 +1,262 @@
+#ifndef DRIVER_H
+#define DRIVER_H
+
+struct driver_ops {
+ const char *name; /* as appears in the config file */
+
+ int (*init)(struct hostapd_data *hapd);
+ void (*deinit)(void *priv);
+
+ int (*wireless_event_init)(void *priv);
+ void (*wireless_event_deinit)(void *priv);
+
+ /**
+ * set_8021x - enable/disable 802.1x support
+ * @priv: driver private data
+ * @enabled: 1 = enable, 0 = disable
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Configure the kernel driver to enable/disable 802.1x support.
+ * This may be an empty function if 802.1x support is always enabled.
+ */
+ int (*set_ieee8021x)(void *priv, int enabled);
+
+ /**
+ * set_privacy - enable/disable privacy
+ * @priv: driver private data
+ * @enabled: 1 = privacy enabled, 0 = disabled
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * Configure privacy.
+ */
+ int (*set_privacy)(void *priv, int enabled);
+
+ int (*set_encryption)(void *priv, const char *alg, u8 *addr,
+ int idx, u8 *key, size_t key_len);
+ int (*get_seqnum)(void *priv, u8 *addr, int idx, u8 *seq);
+ int (*flush)(void *priv);
+ int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+
+ int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
+ u8 *addr);
+ int (*send_eapol)(void *priv, u8 *addr, u8 *data, size_t data_len,
+ int encrypt);
+ int (*set_sta_authorized)(void *driver, u8 *addr, int authorized);
+ int (*sta_deauth)(void *priv, u8 *addr, int reason);
+ int (*sta_disassoc)(void *priv, u8 *addr, int reason);
+ int (*sta_remove)(void *priv, u8 *addr);
+ int (*get_ssid)(void *priv, u8 *buf, int len);
+ int (*set_ssid)(void *priv, u8 *buf, int len);
+ int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
+ int flags);
+ int (*set_assoc_ap)(void *priv, u8 *addr);
+ int (*sta_add)(void *priv, u8 *addr, u16 aid, u16 capability,
+ u8 tx_supp_rates);
+ int (*get_inact_sec)(void *priv, u8 *addr);
+ int (*sta_clear_stats)(void *priv, u8 *addr);
+};
+
+static inline int
+hostapd_driver_init(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->init == NULL)
+ return -1;
+ return hapd->driver->init(hapd);
+}
+
+static inline void
+hostapd_driver_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->deinit == NULL)
+ return;
+ hapd->driver->deinit(hapd->driver);
+}
+
+static inline int
+hostapd_wireless_event_init(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->wireless_event_init == NULL)
+ return 0;
+ return hapd->driver->wireless_event_init(hapd->driver);
+}
+
+static inline void
+hostapd_wireless_event_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->wireless_event_deinit == NULL)
+ return;
+ hapd->driver->wireless_event_deinit(hapd->driver);
+}
+
+static inline int
+hostapd_set_ieee8021x(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
+ return 0;
+ return hapd->driver->set_ieee8021x(hapd->driver, enabled);
+}
+
+static inline int
+hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
+ return 0;
+ return hapd->driver->set_privacy(hapd->driver, enabled);
+}
+
+static inline int
+hostapd_set_encryption(struct hostapd_data *hapd, const char *alg, u8 *addr,
+ int idx, u8 *key, size_t key_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
+ return 0;
+ return hapd->driver->set_encryption(hapd->driver, alg, addr, idx, key,
+ key_len);
+}
+
+static inline int
+hostapd_get_seqnum(struct hostapd_data *hapd, u8 *addr, int idx, u8 *seq)
+{
+ if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
+ return 0;
+ return hapd->driver->get_seqnum(hapd->driver, addr, idx, seq);
+}
+
+static inline int
+hostapd_flush(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->flush == NULL)
+ return 0;
+ return hapd->driver->flush(hapd->driver);
+}
+
+static inline int
+hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
+ size_t elem_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
+ return 0;
+ return hapd->driver->set_generic_elem(hapd->driver, elem, elem_len);
+}
+
+static inline int
+hostapd_read_sta_data(struct hostapd_data *hapd,
+ struct hostap_sta_driver_data *data, u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
+ return -1;
+ return hapd->driver->read_sta_data(hapd->driver, data, addr);
+}
+
+static inline int
+hostapd_send_eapol(struct hostapd_data *hapd, u8 *addr, u8 *data,
+ size_t data_len, int encrypt)
+{
+ if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
+ return 0;
+ return hapd->driver->send_eapol(hapd->driver, addr, data, data_len,
+ encrypt);
+}
+
+static inline int
+hostapd_set_sta_authorized(struct hostapd_data *hapd, u8 *addr, int authorized)
+{
+ if (hapd->driver == NULL || hapd->driver->set_sta_authorized == NULL)
+ return 0;
+ return hapd->driver->set_sta_authorized(hapd->driver, addr,
+ authorized);
+}
+
+static inline int
+hostapd_sta_deauth(struct hostapd_data *hapd, u8 *addr, int reason)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+ return 0;
+ return hapd->driver->sta_deauth(hapd->driver, addr, reason);
+}
+
+static inline int
+hostapd_sta_disassoc(struct hostapd_data *hapd, u8 *addr, int reason)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+ return 0;
+ return hapd->driver->sta_disassoc(hapd->driver, addr, reason);
+}
+
+static inline int
+hostapd_sta_remove(struct hostapd_data *hapd, u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+ return 0;
+ return hapd->driver->sta_remove(hapd->driver, addr);
+}
+
+static inline int
+hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
+ return 0;
+ return hapd->driver->get_ssid(hapd->driver, buf, len);
+}
+
+static inline int
+hostapd_set_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
+ return 0;
+ return hapd->driver->set_ssid(hapd->driver, buf, len);
+}
+
+static inline int
+hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
+ int flags)
+{
+ if (hapd->driver == NULL || hapd->driver->send_mgmt_frame == NULL)
+ return 0;
+ return hapd->driver->send_mgmt_frame(hapd->driver, msg, len, flags);
+}
+
+static inline int
+hostapd_set_assoc_ap(struct hostapd_data *hapd, u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
+ return 0;
+ return hapd->driver->set_assoc_ap(hapd->driver, addr);
+}
+
+static inline int
+hostapd_sta_add(struct hostapd_data *hapd, u8 *addr, u16 aid, u16 capability,
+ u8 tx_supp_rates)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
+ return 0;
+ return hapd->driver->sta_add(hapd->driver, addr, aid, capability,
+ tx_supp_rates);
+}
+
+static inline int
+hostapd_get_inact_sec(struct hostapd_data *hapd, u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+ return 0;
+ return hapd->driver->get_inact_sec(hapd->driver, addr);
+}
+
+
+void driver_register(const char *name, const struct driver_ops *ops);
+void driver_unregister(const char *name);
+const struct driver_ops *driver_lookup(const char *name);
+
+static inline int
+hostapd_sta_clear_stats(struct hostapd_data *hapd, u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
+ return 0;
+ return hapd->driver->sta_clear_stats(hapd->driver, addr);
+}
+
+#endif /* DRIVER_H */
diff --git a/contrib/hostapd/driver_test.c b/contrib/hostapd/driver_test.c
new file mode 100644
index 000000000000..612d1dcc5a24
--- /dev/null
+++ b/contrib/hostapd/driver_test.c
@@ -0,0 +1,78 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / Driver interface for development testing
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "hostapd.h"
+#include "driver.h"
+
+
+struct test_driver_data {
+ struct driver_ops ops;
+ struct hostapd_data *hapd;
+};
+
+static const struct driver_ops test_driver_ops;
+
+
+static int test_driver_init(struct hostapd_data *hapd)
+{
+ struct test_driver_data *drv;
+
+ drv = malloc(sizeof(struct test_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for test driver data\n");
+ return -1;
+ }
+
+ memset(drv, 0, sizeof(*drv));
+ drv->ops = test_driver_ops;
+ drv->hapd = hapd;
+
+ hapd->driver = &drv->ops;
+ return 0;
+}
+
+
+static void test_driver_deinit(void *priv)
+{
+ struct test_driver_data *drv = priv;
+
+ drv->hapd->driver = NULL;
+
+ free(drv);
+}
+
+
+static const struct driver_ops test_driver_ops = {
+ .name = "test",
+ .init = test_driver_init,
+ .deinit = test_driver_deinit,
+};
+
+
+void test_driver_register(void)
+{
+ driver_register(test_driver_ops.name, &test_driver_ops);
+}
diff --git a/contrib/hostapd/driver_wired.c b/contrib/hostapd/driver_wired.c
new file mode 100644
index 000000000000..3e21268514f8
--- /dev/null
+++ b/contrib/hostapd/driver_wired.c
@@ -0,0 +1,395 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / Kernel driver communication
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef USE_KERNEL_HEADERS
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/if_arp.h>
+#include <linux/if.h>
+#else /* USE_KERNEL_HEADERS */
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "driver.h"
+#include "accounting.h"
+
+
+struct wired_driver_data {
+ struct driver_ops ops;
+ struct hostapd_data *hapd;
+
+ int sock; /* raw packet socket for driver access */
+ int dhcp_sock; /* socket for dhcp packets */
+};
+
+static const struct driver_ops wired_driver_ops;
+
+
+#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03}
+
+
+/* TODO: detecting new devices should eventually be changed from using DHCP
+ * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
+ * based on ebtables, etc. */
+
+struct dhcp_message {
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ u_int16_t secs;
+ u_int16_t flags;
+ u_int32_t ciaddr;
+ u_int32_t yiaddr;
+ u_int32_t siaddr;
+ u_int32_t giaddr;
+ u_int8_t chaddr[16];
+ u_int8_t sname[64];
+ u_int8_t file[128];
+ u_int32_t cookie;
+ u_int8_t options[308]; /* 312 - cookie */
+};
+
+
+static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
+{
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ return;
+
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Data frame from unknown STA "
+ MACSTR " - adding a new STA\n", MAC2STR(addr));
+ sta = ap_sta_add(hapd, addr);
+ if (sta) {
+ hostapd_new_assoc_sta(hapd, sta);
+ accounting_sta_get_id(hapd, sta);
+ } else {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Failed to add STA entry "
+ "for " MACSTR "\n", MAC2STR(addr));
+ }
+}
+
+
+static void handle_data(struct hostapd_data *hapd, char *buf, size_t len)
+{
+ struct ieee8023_hdr *hdr;
+ u8 *pos, *sa;
+ size_t left;
+
+ /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
+ * 2 byte ethertype */
+ if (len < 14) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "handle_data: too short "
+ "(%lu)\n", (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee8023_hdr *) buf;
+
+ switch (ntohs(hdr->ethertype)) {
+ case ETH_P_PAE:
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,
+ "Received EAPOL packet\n");
+ sa = hdr->src;
+ wired_possible_new_sta(hapd, sa);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+
+ ieee802_1x_receive(hapd, sa, pos, left);
+ break;
+
+ default:
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "Unknown ethertype 0x%04x in data frame\n",
+ ntohs(hdr->ethertype));
+ break;
+ }
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_data(hapd, buf, len);
+}
+
+
+static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct dhcp_message *msg;
+ u8 *mac_address;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ /* must contain at least dhcp_message->chaddr */
+ if (len < 44) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "handle_dhcp: too short "
+ "(%d)\n", len);
+ return;
+ }
+
+ msg = (struct dhcp_message *) buf;
+ mac_address = (u8 *) &(msg->chaddr);
+
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE,
+ "Got DHCP broadcast packet from " MACSTR "\n",
+ MAC2STR(mac_address));
+
+ wired_possible_new_sta(hapd, mac_address);
+}
+
+
+static int wired_init_sockets(struct wired_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ struct sockaddr_in addr2;
+ struct packet_mreq mreq;
+ u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP;
+ int n = 1;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s",
+ hapd->conf->iface);
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "Opening raw packet socket for ifindex %d\n",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ /* filter multicast address */
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifr.ifr_ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = 6;
+ memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen);
+
+ if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq)) < 0) {
+ perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", hapd->conf->iface);
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ /* setup dhcp listen socket for sta detection */
+ if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket call failed for dhcp");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL))
+ {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&addr2, 0, sizeof(addr2));
+ addr2.sin_family = AF_INET;
+ addr2.sin_port = htons(67);
+ addr2.sin_addr.s_addr = INADDR_ANY;
+
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ return -1;
+ }
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ);
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *) &ifr, sizeof(ifr)) < 0) {
+ perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+ return -1;
+ }
+
+ if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
+ sizeof(struct sockaddr)) == -1) {
+ perror("bind");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wired_send_eapol(void *priv, u8 *addr,
+ u8 *data, size_t data_len, int encrypt)
+{
+ struct wired_driver_data *drv = priv;
+
+ struct ieee8023_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = malloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for wired_send_eapol(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ memset(hdr, 0, len);
+ memcpy(hdr->dest, addr, ETH_ALEN);
+ memcpy(hdr->src, drv->hapd->own_addr, ETH_ALEN);
+ hdr->ethertype = htons(ETH_P_PAE);
+
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, data, data_len);
+
+ res = send(drv->sock, (u8 *) hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("wired_send_eapol: send");
+ printf("wired_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static int wired_driver_init(struct hostapd_data *hapd)
+{
+ struct wired_driver_data *drv;
+
+ drv = malloc(sizeof(struct wired_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for wired driver data\n");
+ return -1;
+ }
+
+ memset(drv, 0, sizeof(*drv));
+ drv->ops = wired_driver_ops;
+ drv->hapd = hapd;
+
+ if (wired_init_sockets(drv))
+ return -1;
+
+ hapd->driver = &drv->ops;
+ return 0;
+}
+
+
+static void wired_driver_deinit(void *priv)
+{
+ struct wired_driver_data *drv = priv;
+
+ drv->hapd->driver = NULL;
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ if (drv->dhcp_sock >= 0)
+ close(drv->dhcp_sock);
+
+ free(drv);
+}
+
+
+static const struct driver_ops wired_driver_ops = {
+ .name = "wired",
+ .init = wired_driver_init,
+ .deinit = wired_driver_deinit,
+ .send_eapol = wired_send_eapol,
+};
+
+void wired_driver_register(void)
+{
+ driver_register(wired_driver_ops.name, &wired_driver_ops);
+}
diff --git a/contrib/hostapd/eap.c b/contrib/hostapd/eap.c
new file mode 100644
index 000000000000..7a21c802e5a4
--- /dev/null
+++ b/contrib/hostapd/eap.c
@@ -0,0 +1,911 @@
+/*
+ * hostapd / EAP Standalone Authenticator state machine
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "hostapd.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "eap_i.h"
+
+
+extern const struct eap_method eap_method_identity;
+#ifdef EAP_MD5
+extern const struct eap_method eap_method_md5;
+#endif /* EAP_MD5 */
+#ifdef EAP_TLS
+extern const struct eap_method eap_method_tls;
+#endif /* EAP_TLS */
+#ifdef EAP_MSCHAPv2
+extern const struct eap_method eap_method_mschapv2;
+#endif /* EAP_MSCHAPv2 */
+#ifdef EAP_PEAP
+extern const struct eap_method eap_method_peap;
+#endif /* EAP_PEAP */
+#ifdef EAP_TLV
+extern const struct eap_method eap_method_tlv;
+#endif /* EAP_TLV */
+#ifdef EAP_GTC
+extern const struct eap_method eap_method_gtc;
+#endif /* EAP_GTC */
+#ifdef EAP_TTLS
+extern const struct eap_method eap_method_ttls;
+#endif /* EAP_TTLS */
+#ifdef EAP_SIM
+extern const struct eap_method eap_method_sim;
+#endif /* EAP_SIM */
+
+static const struct eap_method *eap_methods[] =
+{
+ &eap_method_identity,
+#ifdef EAP_MD5
+ &eap_method_md5,
+#endif /* EAP_MD5 */
+#ifdef EAP_TLS
+ &eap_method_tls,
+#endif /* EAP_TLS */
+#ifdef EAP_MSCHAPv2
+ &eap_method_mschapv2,
+#endif /* EAP_MSCHAPv2 */
+#ifdef EAP_PEAP
+ &eap_method_peap,
+#endif /* EAP_PEAP */
+#ifdef EAP_TTLS
+ &eap_method_ttls,
+#endif /* EAP_TTLS */
+#ifdef EAP_TLV
+ &eap_method_tlv,
+#endif /* EAP_TLV */
+#ifdef EAP_GTC
+ &eap_method_gtc,
+#endif /* EAP_GTC */
+#ifdef EAP_SIM
+ &eap_method_sim,
+#endif /* EAP_SIM */
+};
+#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
+
+
+const struct eap_method * eap_sm_get_eap_methods(int method)
+{
+ int i;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (eap_methods[i]->method == method)
+ return eap_methods[i];
+ }
+ return NULL;
+}
+
+static void eap_user_free(struct eap_user *user);
+
+
+/* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
+
+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
+ int eapSRTT, int eapRTTVAR,
+ int methodTimeout);
+static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
+static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
+static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
+static int eap_sm_nextId(struct eap_sm *sm, int id);
+static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
+static int eap_sm_Policy_getDecision(struct eap_sm *sm);
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+
+
+/* Definitions for clarifying state machine implementation */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
+ int global)
+
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(struct eap_sm *sm)
+
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+
+static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+{
+ return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
+ Boolean value)
+{
+ sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
+}
+
+
+static void eapol_set_eapReqData(struct eap_sm *sm,
+ const u8 *eapReqData, size_t eapReqDataLen)
+{
+ wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
+ sm->eapReqData, sm->eapReqDataLen);
+ sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
+}
+
+
+static void eapol_set_eapKeyData(struct eap_sm *sm,
+ const u8 *eapKeyData, size_t eapKeyDataLen)
+{
+ wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
+ sm->eapKeyData, sm->eapKeyDataLen);
+ sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
+}
+
+
+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
+ int phase2)
+{
+ struct eap_user *user;
+
+ if (sm == NULL || sm->eapol_cb == NULL ||
+ sm->eapol_cb->get_eap_user == NULL)
+ return -1;
+
+ eap_user_free(sm->user);
+ sm->user = NULL;
+
+ user = malloc(sizeof(*user));
+ if (user == NULL)
+ return -1;
+ memset(user, 0, sizeof(*user));
+
+ if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
+ identity_len, phase2, user) != 0) {
+ eap_user_free(user);
+ return -1;
+ }
+
+ sm->user = user;
+ sm->user_eap_method_index = 0;
+
+ return 0;
+}
+
+
+SM_STATE(EAP, DISABLED)
+{
+ SM_ENTRY(EAP, DISABLED);
+}
+
+
+SM_STATE(EAP, INITIALIZE)
+{
+ SM_ENTRY(EAP, INITIALIZE);
+
+ sm->currentId = -1;
+ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+ eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+ eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
+ free(sm->eapKeyData);
+ sm->eapKeyData = NULL;
+ sm->eapKeyDataLen = 0;
+ /* eapKeyAvailable = FALSE */
+ eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+
+ /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
+ * method state needs to be reseted here so that it does not remain in
+ * success state when re-authentication starts. */
+ if (sm->m && sm->eap_method_priv) {
+ sm->m->reset(sm, sm->eap_method_priv);
+ sm->eap_method_priv = NULL;
+ }
+ sm->m = NULL;
+ sm->user_eap_method_index = 0;
+
+ if (sm->backend_auth) {
+ sm->currentMethod = EAP_TYPE_NONE;
+ /* parse rxResp, respId, respMethod */
+ eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
+ if (sm->rxResp) {
+ sm->currentId = sm->respId;
+ }
+ }
+}
+
+
+SM_STATE(EAP, PICK_UP_METHOD)
+{
+ SM_ENTRY(EAP, PICK_UP_METHOD);
+
+ if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
+ sm->currentMethod = sm->respMethod;
+ if (sm->m && sm->eap_method_priv) {
+ sm->m->reset(sm, sm->eap_method_priv);
+ sm->eap_method_priv = NULL;
+ }
+ sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+ if (sm->m && sm->m->initPickUp) {
+ sm->eap_method_priv = sm->m->initPickUp(sm);
+ if (sm->eap_method_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Failed to "
+ "initialize EAP method %d",
+ sm->currentMethod);
+ sm->m = NULL;
+ sm->currentMethod = EAP_TYPE_NONE;
+ }
+ } else {
+ sm->m = NULL;
+ sm->currentMethod = EAP_TYPE_NONE;
+ }
+ }
+}
+
+
+SM_STATE(EAP, IDLE)
+{
+ SM_ENTRY(EAP, IDLE);
+
+ sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
+ sm->eapSRTT, sm->eapRTTVAR,
+ sm->methodTimeout);
+}
+
+
+SM_STATE(EAP, RETRANSMIT)
+{
+ SM_ENTRY(EAP, RETRANSMIT);
+
+ /* TODO: Is this needed since EAPOL state machines take care of
+ * retransmit? */
+}
+
+
+SM_STATE(EAP, RECEIVED)
+{
+ SM_ENTRY(EAP, RECEIVED);
+
+ /* parse rxResp, respId, respMethod */
+ eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
+}
+
+
+SM_STATE(EAP, DISCARD)
+{
+ SM_ENTRY(EAP, DISCARD);
+ eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
+}
+
+
+SM_STATE(EAP, SEND_REQUEST)
+{
+ SM_ENTRY(EAP, SEND_REQUEST);
+
+ sm->retransCount = 0;
+ if (sm->eapReqData) {
+ eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
+ free(sm->lastReqData);
+ sm->lastReqData = sm->eapReqData;
+ sm->lastReqDataLen = sm->eapReqDataLen;
+ sm->eapReqData = NULL;
+ sm->eapReqDataLen = 0;
+ eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, TRUE);
+ } else {
+ wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
+ eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
+ }
+}
+
+
+SM_STATE(EAP, INTEGRITY_CHECK)
+{
+ SM_ENTRY(EAP, INTEGRITY_CHECK);
+
+ if (sm->m->check) {
+ sm->ignore = sm->m->check(sm, sm->eap_method_priv,
+ sm->eapRespData, sm->eapRespDataLen);
+ }
+}
+
+
+SM_STATE(EAP, METHOD_REQUEST)
+{
+ SM_ENTRY(EAP, METHOD_REQUEST);
+
+ if (sm->m == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: method not initialized");
+ return;
+ }
+
+ sm->currentId = eap_sm_nextId(sm, sm->currentId);
+ wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
+ sm->currentId);
+ sm->lastId = sm->currentId;
+ free(sm->eapReqData);
+ sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
+ sm->currentId, &sm->eapReqDataLen);
+ if (sm->m->getTimeout)
+ sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
+ else
+ sm->methodTimeout = 0;
+}
+
+
+SM_STATE(EAP, METHOD_RESPONSE)
+{
+ SM_ENTRY(EAP, METHOD_RESPONSE);
+
+ sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
+ sm->eapRespDataLen);
+ if (sm->m->isDone(sm, sm->eap_method_priv)) {
+ eap_sm_Policy_update(sm, NULL, 0);
+ free(sm->eapKeyData);
+ if (sm->m->getKey) {
+ sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
+ &sm->eapKeyDataLen);
+ } else {
+ sm->eapKeyData = NULL;
+ sm->eapKeyDataLen = 0;
+ }
+ sm->methodState = METHOD_END;
+ } else {
+ sm->methodState = METHOD_CONTINUE;
+ }
+}
+
+
+SM_STATE(EAP, PROPOSE_METHOD)
+{
+ SM_ENTRY(EAP, PROPOSE_METHOD);
+
+ sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
+ if (sm->m && sm->eap_method_priv) {
+ sm->m->reset(sm, sm->eap_method_priv);
+ sm->eap_method_priv = NULL;
+ }
+ sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+ if (sm->m) {
+ sm->eap_method_priv = sm->m->init(sm);
+ if (sm->eap_method_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
+ "method %d", sm->currentMethod);
+ sm->m = NULL;
+ sm->currentMethod = EAP_TYPE_NONE;
+ }
+ }
+ if (sm->currentMethod == EAP_TYPE_IDENTITY ||
+ sm->currentMethod == EAP_TYPE_NOTIFICATION)
+ sm->methodState = METHOD_CONTINUE;
+ else
+ sm->methodState = METHOD_PROPOSED;
+}
+
+
+SM_STATE(EAP, NAK)
+{
+ struct eap_hdr *nak;
+ size_t len = 0;
+ u8 *pos, *nak_list = NULL;
+
+ SM_ENTRY(EAP, NAK);
+
+ if (sm->eap_method_priv) {
+ sm->m->reset(sm, sm->eap_method_priv);
+ sm->eap_method_priv = NULL;
+ }
+ sm->m = NULL;
+
+ nak = (struct eap_hdr *) sm->eapRespData;
+ if (nak && sm->eapRespDataLen > sizeof(*nak)) {
+ len = ntohs(nak->length);
+ if (len > sm->eapRespDataLen)
+ len = sm->eapRespDataLen;
+ pos = (u8 *) (nak + 1);
+ len -= sizeof(*nak);
+ if (*pos == EAP_TYPE_NAK) {
+ pos++;
+ len--;
+ nak_list = pos;
+ }
+ }
+ eap_sm_Policy_update(sm, nak_list, len);
+}
+
+
+SM_STATE(EAP, SELECT_ACTION)
+{
+ SM_ENTRY(EAP, SELECT_ACTION);
+
+ sm->decision = eap_sm_Policy_getDecision(sm);
+}
+
+
+SM_STATE(EAP, TIMEOUT_FAILURE)
+{
+ SM_ENTRY(EAP, TIMEOUT_FAILURE);
+
+ eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
+}
+
+
+SM_STATE(EAP, FAILURE)
+{
+ SM_ENTRY(EAP, FAILURE);
+
+ free(sm->eapReqData);
+ sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
+ &sm->eapReqDataLen);
+ if (sm->eapReqData) {
+ eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
+ free(sm->eapReqData);
+ sm->eapReqData = NULL;
+ sm->eapReqDataLen = 0;
+ }
+ free(sm->lastReqData);
+ sm->lastReqData = NULL;
+ sm->lastReqDataLen = 0;
+ eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+}
+
+
+SM_STATE(EAP, SUCCESS)
+{
+ SM_ENTRY(EAP, SUCCESS);
+
+ free(sm->eapReqData);
+ sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
+ &sm->eapReqDataLen);
+ if (sm->eapReqData) {
+ eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
+ free(sm->eapReqData);
+ sm->eapReqData = NULL;
+ sm->eapReqDataLen = 0;
+ }
+ free(sm->lastReqData);
+ sm->lastReqData = NULL;
+ sm->lastReqDataLen = 0;
+ if (sm->eapKeyData) {
+ eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
+ }
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+}
+
+
+SM_STEP(EAP)
+{
+ if (eapol_get_bool(sm, EAPOL_eapRestart) &&
+ eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER_GLOBAL(EAP, INITIALIZE);
+ else if (!eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER_GLOBAL(EAP, DISABLED);
+ else switch (sm->EAP_state) {
+ case EAP_INITIALIZE:
+ if (sm->backend_auth) {
+ if (!sm->rxResp)
+ SM_ENTER(EAP, SELECT_ACTION);
+ else if (sm->rxResp &&
+ (sm->respMethod == EAP_TYPE_NAK ||
+ sm->respMethod == EAP_TYPE_EXPANDED_NAK))
+ SM_ENTER(EAP, NAK);
+ else
+ SM_ENTER(EAP, PICK_UP_METHOD);
+ } else {
+ SM_ENTER(EAP, SELECT_ACTION);
+ }
+ break;
+ case EAP_PICK_UP_METHOD:
+ if (sm->currentMethod == EAP_TYPE_NONE) {
+ SM_ENTER(EAP, SELECT_ACTION);
+ } else {
+ SM_ENTER(EAP, METHOD_RESPONSE);
+ }
+ break;
+ case EAP_DISABLED:
+ if (eapol_get_bool(sm, EAPOL_portEnabled))
+ SM_ENTER(EAP, INITIALIZE);
+ break;
+ case EAP_IDLE:
+ if (sm->retransWhile == 0)
+ SM_ENTER(EAP, RETRANSMIT);
+ else if (eapol_get_bool(sm, EAPOL_eapResp))
+ SM_ENTER(EAP, RECEIVED);
+ break;
+ case EAP_RETRANSMIT:
+ if (sm->retransCount > sm->MaxRetrans)
+ SM_ENTER(EAP, TIMEOUT_FAILURE);
+ else
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_RECEIVED:
+ if (sm->rxResp && (sm->respId == sm->currentId) &&
+ (sm->respMethod == EAP_TYPE_NAK ||
+ sm->respMethod == EAP_TYPE_EXPANDED_NAK)
+ && (sm->methodState == METHOD_PROPOSED))
+ SM_ENTER(EAP, NAK);
+ else if (sm->rxResp && (sm->respId == sm->currentId) &&
+ (sm->respMethod == sm->currentMethod))
+ SM_ENTER(EAP, INTEGRITY_CHECK);
+ else
+ SM_ENTER(EAP, DISCARD);
+ break;
+ case EAP_DISCARD:
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_SEND_REQUEST:
+ SM_ENTER(EAP, IDLE);
+ break;
+ case EAP_INTEGRITY_CHECK:
+ if (sm->ignore)
+ SM_ENTER(EAP, DISCARD);
+ else
+ SM_ENTER(EAP, METHOD_RESPONSE);
+ break;
+ case EAP_METHOD_REQUEST:
+ SM_ENTER(EAP, SEND_REQUEST);
+ break;
+ case EAP_METHOD_RESPONSE:
+ if (sm->methodState == METHOD_END)
+ SM_ENTER(EAP, SELECT_ACTION);
+ else
+ SM_ENTER(EAP, METHOD_REQUEST);
+ break;
+ case EAP_PROPOSE_METHOD:
+ SM_ENTER(EAP, METHOD_REQUEST);
+ break;
+ case EAP_NAK:
+ SM_ENTER(EAP, SELECT_ACTION);
+ break;
+ case EAP_SELECT_ACTION:
+ if (sm->decision == DECISION_FAILURE)
+ SM_ENTER(EAP, FAILURE);
+ else if (sm->decision == DECISION_SUCCESS)
+ SM_ENTER(EAP, SUCCESS);
+ else
+ SM_ENTER(EAP, PROPOSE_METHOD);
+ break;
+ case EAP_TIMEOUT_FAILURE:
+ break;
+ case EAP_FAILURE:
+ break;
+ case EAP_SUCCESS:
+ break;
+ }
+}
+
+
+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
+ int eapSRTT, int eapRTTVAR,
+ int methodTimeout)
+{
+ /* For now, retransmission is done in EAPOL state machines, so make
+ * sure EAP state machine does not end up trying to retransmit packets.
+ */
+ return 1;
+}
+
+
+static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
+{
+ struct eap_hdr *hdr;
+ size_t plen;
+
+ /* parse rxResp, respId, respMethod */
+ sm->rxResp = FALSE;
+ sm->respId = -1;
+ sm->respMethod = EAP_TYPE_NONE;
+
+ if (resp == NULL || len < sizeof(*hdr))
+ return;
+
+ hdr = (struct eap_hdr *) resp;
+ plen = ntohs(hdr->length);
+ if (plen > len) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
+ "(len=%lu plen=%lu)", (unsigned long) len,
+ (unsigned long) plen);
+ return;
+ }
+
+ sm->respId = hdr->identifier;
+
+ if (hdr->code == EAP_CODE_RESPONSE)
+ sm->rxResp = TRUE;
+
+ if (len > sizeof(*hdr))
+ sm->respMethod = *((u8 *) (hdr + 1));
+
+ wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
+ "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
+}
+
+
+static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
+{
+ struct eap_hdr *resp;
+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
+
+ *len = sizeof(*resp);
+ resp = malloc(*len);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_SUCCESS;
+ resp->identifier = id;
+ resp->length = htons(*len);
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
+{
+ struct eap_hdr *resp;
+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
+
+ *len = sizeof(*resp);
+ resp = malloc(*len);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_FAILURE;
+ resp->identifier = id;
+ resp->length = htons(*len);
+
+ return (u8 *) resp;
+}
+
+
+static int eap_sm_nextId(struct eap_sm *sm, int id)
+{
+ if (id < 0) {
+ /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
+ * random number */
+ id = rand() & 0xff;
+ if (id != sm->lastId)
+ return id;
+ }
+ return (id + 1) & 0xff;
+}
+
+
+void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
+{
+ int i, j;
+
+ wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
+ "index %d)", sm->user_eap_method_index);
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
+ sm->user->methods, EAP_MAX_METHODS);
+ wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
+ nak_list, len);
+
+ i = sm->user_eap_method_index;
+ while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
+ for (j = 0; j < len; j++) {
+ if (nak_list[j] == sm->user->methods[i]) {
+ break;
+ }
+ }
+
+ if (j < len) {
+ /* found */
+ i++;
+ continue;
+ }
+
+ /* not found - remove from the list */
+ memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
+ EAP_MAX_METHODS - i - 1);
+ sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
+ sm->user->methods, EAP_MAX_METHODS);
+}
+
+
+static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
+{
+ if (nak_list == NULL || sm == NULL || sm->user == NULL)
+ return;
+
+ if (sm->user->phase2) {
+ wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
+ " info was selected - reject");
+ sm->decision = DECISION_FAILURE;
+ return;
+ }
+
+ eap_sm_process_nak(sm, nak_list, len);
+}
+
+
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
+{
+ EapType next;
+
+ /* In theory, there should be no problems with starting
+ * re-authentication with something else than EAP-Request/Identity and
+ * this does indeed work with wpa_supplicant. However, at least Funk
+ * Supplicant seemed to ignore re-auth if it skipped
+ * EAP-Request/Identity.
+ * Re-auth sets currentId == -1, so that can be used here to select
+ * whether Identity needs to be requested again. */
+ if (sm->identity == NULL || sm->currentId == -1) {
+ next = EAP_TYPE_IDENTITY;
+ sm->update_user = TRUE;
+ } else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index] !=
+ EAP_TYPE_NONE) {
+ next = sm->user->methods[sm->user_eap_method_index++];
+ } else {
+ next = EAP_TYPE_NONE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
+ return next;
+}
+
+
+static int eap_sm_Policy_getDecision(struct eap_sm *sm)
+{
+ if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
+ sm->m->isSuccess(sm, sm->eap_method_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
+ "SUCCESS");
+ sm->update_user = TRUE;
+ return DECISION_SUCCESS;
+ }
+
+ if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
+ !sm->m->isSuccess(sm, sm->eap_method_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
+ "FAILURE");
+ sm->update_user = TRUE;
+ return DECISION_FAILURE;
+ }
+
+ if ((sm->user == NULL || sm->update_user) && sm->identity) {
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
+ "found from database -> FAILURE");
+ return DECISION_FAILURE;
+ }
+ sm->update_user = FALSE;
+ }
+
+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
+ "available -> CONTINUE");
+ return DECISION_CONTINUE;
+ }
+
+ if (sm->identity == NULL || sm->currentId == -1) {
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
+ "yet -> CONTINUE");
+ return DECISION_CONTINUE;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
+ "FAILURE");
+ return DECISION_FAILURE;
+}
+
+
+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
+{
+ return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
+}
+
+
+int eap_sm_step(struct eap_sm *sm)
+{
+ int res = 0;
+ do {
+ sm->changed = FALSE;
+ SM_STEP_RUN(EAP);
+ if (sm->changed)
+ res = 1;
+ } while (sm->changed);
+ return res;
+}
+
+
+u8 eap_get_type(const char *name)
+{
+ int i;
+ for (i = 0; i < NUM_EAP_METHODS; i++) {
+ if (strcmp(eap_methods[i]->name, name) == 0)
+ return eap_methods[i]->method;
+ }
+ return EAP_TYPE_NONE;
+}
+
+
+void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
+ size_t eapRespDataLen)
+{
+ if (sm == NULL)
+ return;
+ free(sm->eapRespData);
+ sm->eapRespData = malloc(eapRespDataLen);
+ if (sm->eapRespData == NULL)
+ return;
+ memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
+ sm->eapRespDataLen = eapRespDataLen;
+ wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
+ eapRespData, eapRespDataLen);
+}
+
+
+static void eap_user_free(struct eap_user *user)
+{
+ if (user == NULL)
+ return;
+ free(user->password);
+ user->password = NULL;
+ free(user);
+}
+
+
+struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ struct eap_config *eap_conf)
+{
+ struct eap_sm *sm;
+
+ sm = malloc(sizeof(*sm));
+ if (sm == NULL)
+ return NULL;
+ memset(sm, 0, sizeof(*sm));
+ sm->eapol_ctx = eapol_ctx;
+ sm->eapol_cb = eapol_cb;
+ sm->MaxRetrans = 10;
+ sm->ssl_ctx = eap_conf->ssl_ctx;
+ sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
+ sm->backend_auth = eap_conf->backend_auth;
+
+ wpa_printf(MSG_DEBUG, "EAP: State machine created");
+
+ return sm;
+}
+
+
+void eap_sm_deinit(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "EAP: State machine removed");
+ if (sm->m && sm->eap_method_priv)
+ sm->m->reset(sm, sm->eap_method_priv);
+ free(sm->eapReqData);
+ free(sm->eapKeyData);
+ free(sm->lastReqData);
+ free(sm->eapRespData);
+ free(sm->identity);
+ eap_user_free(sm->user);
+ free(sm);
+}
diff --git a/contrib/hostapd/eap.h b/contrib/hostapd/eap.h
new file mode 100644
index 000000000000..01f47dad12e4
--- /dev/null
+++ b/contrib/hostapd/eap.h
@@ -0,0 +1,83 @@
+#ifndef EAP_H
+#define EAP_H
+
+#include "defs.h"
+#include "eap_defs.h"
+
+struct eap_sm;
+
+#define EAP_MAX_METHODS 8
+struct eap_user {
+ u8 methods[EAP_MAX_METHODS];
+ u8 *password;
+ size_t password_len;
+ int phase2;
+ int force_version;
+};
+
+enum eapol_bool_var {
+ EAPOL_eapSuccess, EAPOL_eapRestart, EAPOL_eapFail, EAPOL_eapResp,
+ EAPOL_eapReq, EAPOL_eapNoReq, EAPOL_portEnabled, EAPOL_eapTimeout
+};
+
+struct eapol_callbacks {
+ Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+ void (*set_bool)(void *ctx, enum eapol_bool_var variable,
+ Boolean value);
+ void (*set_eapReqData)(void *ctx, const u8 *eapReqData,
+ size_t eapReqDataLen);
+ void (*set_eapKeyData)(void *ctx, const u8 *eapKeyData,
+ size_t eapKeyDataLen);
+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+ int phase2, struct eap_user *user);
+};
+
+struct eap_config {
+ void *ssl_ctx;
+ void *eap_sim_db_priv;
+ Boolean backend_auth;
+};
+
+
+#ifdef EAP_AUTHENTICATOR
+
+struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ struct eap_config *eap_conf);
+void eap_sm_deinit(struct eap_sm *sm);
+int eap_sm_step(struct eap_sm *sm);
+u8 eap_get_type(const char *name);
+void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
+ size_t eapRespDataLen);
+
+#else /* EAP_AUTHENTICATOR */
+
+static inline struct eap_sm * eap_sm_init(void *eapol_ctx,
+ struct eapol_callbacks *eapol_cb,
+ struct eap_config *eap_conf)
+{
+ return NULL;
+}
+
+static inline void eap_sm_deinit(struct eap_sm *sm)
+{
+}
+
+static inline int eap_sm_step(struct eap_sm *sm)
+{
+ return 0;
+}
+
+static inline u8 eap_get_type(const char *name)
+{
+ return EAP_TYPE_NONE;
+}
+
+static inline void eap_set_eapRespData(struct eap_sm *sm,
+ const u8 *eapRespData,
+ size_t eapRespDataLen)
+{
+}
+
+#endif /* EAP_AUTHENTICATOR */
+
+#endif /* EAP_H */
diff --git a/contrib/hostapd/eap_defs.h b/contrib/hostapd/eap_defs.h
new file mode 100644
index 000000000000..effe665f0919
--- /dev/null
+++ b/contrib/hostapd/eap_defs.h
@@ -0,0 +1,41 @@
+#ifndef EAP_DEFS_H
+#define EAP_DEFS_H
+
+/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+
+struct eap_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code and identifier */
+ /* followed by length-4 octets of data */
+} __attribute__ ((packed));
+
+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
+ EAP_CODE_FAILURE = 4 };
+
+/* EAP Request and Response data begins with one octet Type. Success and
+ * Failure do not have additional data. */
+
+typedef enum {
+ EAP_TYPE_NONE = 0,
+ EAP_TYPE_IDENTITY = 1,
+ EAP_TYPE_NOTIFICATION = 2,
+ EAP_TYPE_NAK = 3 /* Response only */,
+ EAP_TYPE_MD5 = 4,
+ EAP_TYPE_OTP = 5 /* RFC 2284 */,
+ EAP_TYPE_GTC = 6, /* RFC 2284 */
+ EAP_TYPE_TLS = 13 /* RFC 2716 */,
+ EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
+ EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
+ EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
+ EAP_TYPE_AKA = 23 /* draft-arkko-pppext-eap-aka-12.txt */,
+ EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
+ EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
+ EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
+ EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
+ EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
+ EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
+ * draft-bersani-eap-psk-03 */
+} EapType;
+
+#endif /* EAP_DEFS_H */
diff --git a/contrib/hostapd/eap_gtc.c b/contrib/hostapd/eap_gtc.c
new file mode 100644
index 000000000000..674f83735f1f
--- /dev/null
+++ b/contrib/hostapd/eap_gtc.c
@@ -0,0 +1,158 @@
+/*
+ * hostapd / EAP-GTC (RFC 3748)
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+
+
+struct eap_gtc_data {
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_gtc_init(struct eap_sm *sm)
+{
+ struct eap_gtc_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void eap_gtc_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_gtc_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_gtc_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_gtc_data *data = priv;
+ struct eap_hdr *req;
+ u8 *pos;
+ char *msg = "Password";
+ size_t msg_len;
+
+ msg_len = strlen(msg);
+ *reqDataLen = sizeof(*req) + 1 + msg_len;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
+ "request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_GTC;
+ memcpy(pos, msg, msg_len);
+
+ data->state = CONTINUE;
+
+ return (u8 *) req;
+}
+
+
+static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_GTC ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_gtc_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_gtc_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t rlen;
+
+ if (sm->user == NULL || sm->user->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+ data->state = FAILURE;
+ return;
+ }
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ rlen = ntohs(resp->length) - sizeof(*resp) - 1;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
+
+ if (rlen != sm->user->password_len ||
+ memcmp(pos, sm->user->password, rlen) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure");
+ data->state = FAILURE;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success");
+ data->state = SUCCESS;
+ }
+}
+
+
+static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_gtc_data *data = priv;
+ return data->state != CONTINUE;
+}
+
+
+static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_gtc_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_gtc =
+{
+ .method = EAP_TYPE_GTC,
+ .name = "GTC",
+ .init = eap_gtc_init,
+ .reset = eap_gtc_reset,
+ .buildReq = eap_gtc_buildReq,
+ .check = eap_gtc_check,
+ .process = eap_gtc_process,
+ .isDone = eap_gtc_isDone,
+ .isSuccess = eap_gtc_isSuccess,
+};
diff --git a/contrib/hostapd/eap_i.h b/contrib/hostapd/eap_i.h
new file mode 100644
index 000000000000..39b02579ef25
--- /dev/null
+++ b/contrib/hostapd/eap_i.h
@@ -0,0 +1,110 @@
+#ifndef EAP_I_H
+#define EAP_I_H
+
+#include "eap.h"
+
+/* draft-ietf-eap-statemachine-05.pdf - EAP Standalone Authenticator */
+
+struct eap_method {
+ EapType method;
+ const char *name;
+
+ void * (*init)(struct eap_sm *sm);
+ void * (*initPickUp)(struct eap_sm *sm);
+ void (*reset)(struct eap_sm *sm, void *priv);
+
+ u8 * (*buildReq)(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen);
+ int (*getTimeout)(struct eap_sm *sm, void *priv);
+ Boolean (*check)(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen);
+ void (*process)(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen);
+ Boolean (*isDone)(struct eap_sm *sm, void *priv);
+ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
+ /* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
+ * but it is useful in implementing Policy.getDecision() */
+ Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+};
+
+struct eap_sm {
+ enum {
+ EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
+ EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST,
+ EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST,
+ EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE,
+ EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD
+ } EAP_state;
+
+ /* Constants */
+ int MaxRetrans;
+
+ /* Lower layer to standalone authenticator variables */
+ /* eapResp: eapol_sm->be_auth.eapResp */
+ /* portEnabled: eapol_sm->portEnabled */
+ /* eapRestart: eapol_sm->auth_pae.eapRestart */
+ u8 *eapRespData;
+ size_t eapRespDataLen;
+ int retransWhile;
+ int eapSRTT;
+ int eapRTTVAR;
+
+ /* Standalone authenticator to lower layer variables */
+ /* eapReq: eapol_sm->be_auth.eapReq */
+ /* eapNoReq: eapol_sm->be_auth.eapNoReq */
+ /* eapSuccess: eapol_sm->eapSuccess */
+ /* eapFail: eapol_sm->eapFail */
+ /* eapTimeout: eapol_sm->eapTimeout */
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+ u8 *eapKeyData; /* also eapKeyAvailable (boolean) */
+ size_t eapKeyDataLen;
+
+ /* Standalone authenticator state machine local variables */
+
+ /* Long-term (maintained betwen packets) */
+ EapType currentMethod;
+ int currentId;
+ enum {
+ METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END
+ } methodState;
+ int retransCount;
+ u8 *lastReqData;
+ size_t lastReqDataLen;
+ int methodTimeout;
+
+ /* Short-term (not maintained between packets) */
+ Boolean rxResp;
+ int respId;
+ EapType respMethod;
+ Boolean ignore;
+ enum {
+ DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE
+ } decision;
+
+ /* Miscellaneous variables */
+ const struct eap_method *m; /* selected EAP method */
+ /* not defined in draft-ietf-eap-statemachine-02 */
+ Boolean changed;
+ void *eapol_ctx, *msg_ctx;
+ struct eapol_callbacks *eapol_cb;
+ void *eap_method_priv;
+ u8 *identity;
+ size_t identity_len;
+ int lastId; /* Identifier used in the last EAP-Packet */
+ struct eap_user *user;
+ int user_eap_method_index;
+ int init_phase2;
+ void *ssl_ctx;
+ enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
+ void *eap_sim_db_priv;
+ Boolean backend_auth;
+ Boolean update_user;
+};
+
+const struct eap_method * eap_sm_get_eap_methods(int method);
+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
+ int phase2);
+void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len);
+
+#endif /* EAP_I_H */
diff --git a/contrib/hostapd/eap_identity.c b/contrib/hostapd/eap_identity.c
new file mode 100644
index 000000000000..31aedc4e8255
--- /dev/null
+++ b/contrib/hostapd/eap_identity.c
@@ -0,0 +1,174 @@
+/*
+ * hostapd / EAP-Identity
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+
+
+struct eap_identity_data {
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+ int pick_up;
+};
+
+
+static void * eap_identity_init(struct eap_sm *sm)
+{
+ struct eap_identity_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void * eap_identity_initPickUp(struct eap_sm *sm)
+{
+ struct eap_identity_data *data;
+ data = eap_identity_init(sm);
+ if (data) {
+ data->pick_up = 1;
+ }
+ return data;
+}
+
+
+static void eap_identity_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_identity_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_identity_data *data = priv;
+ struct eap_hdr *req;
+ u8 *pos;
+
+ *reqDataLen = sizeof(*req) + 1;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
+ "memory for request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos = EAP_TYPE_IDENTITY;
+
+ return (u8 *) req;
+}
+
+
+static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_IDENTITY ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_identity_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_identity_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos;
+ int len;
+
+ if (data->pick_up) {
+ if (eap_identity_check(sm, data, respData, respDataLen)) {
+ wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick "
+ "up already started negotiation");
+ data->state = FAILURE;
+ return;
+ }
+ data->pick_up = 0;
+ }
+
+ resp = (struct eap_hdr *) respData;
+ len = ntohs(resp->length);
+ pos = (u8 *) (resp + 1);
+ pos++;
+ len -= sizeof(*resp) + 1;
+ if (len < 0) {
+ data->state = FAILURE;
+ return;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
+ free(sm->identity);
+ sm->identity = malloc(len);
+ if (sm->identity == NULL) {
+ data->state = FAILURE;
+ } else {
+ memcpy(sm->identity, pos, len);
+ sm->identity_len = len;
+ data->state = SUCCESS;
+ }
+}
+
+
+static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_identity_data *data = priv;
+ return data->state != CONTINUE;
+}
+
+
+static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_identity_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_identity =
+{
+ .method = EAP_TYPE_IDENTITY,
+ .name = "Identity",
+ .init = eap_identity_init,
+ .initPickUp = eap_identity_initPickUp,
+ .reset = eap_identity_reset,
+ .buildReq = eap_identity_buildReq,
+ .check = eap_identity_check,
+ .process = eap_identity_process,
+ .isDone = eap_identity_isDone,
+ .isSuccess = eap_identity_isSuccess,
+};
diff --git a/contrib/hostapd/eap_md5.c b/contrib/hostapd/eap_md5.c
new file mode 100644
index 000000000000..5675c500d234
--- /dev/null
+++ b/contrib/hostapd/eap_md5.c
@@ -0,0 +1,180 @@
+/*
+ * hostapd / EAP-MD5 server
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "md5.h"
+
+
+#define CHALLENGE_LEN 16
+
+struct eap_md5_data {
+ u8 challenge[CHALLENGE_LEN];
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_md5_init(struct eap_sm *sm)
+{
+ struct eap_md5_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void eap_md5_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_md5_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_md5_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_md5_data *data = priv;
+ struct eap_hdr *req;
+ u8 *pos;
+
+ if (hostapd_get_rand(data->challenge, CHALLENGE_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ *reqDataLen = sizeof(*req) + 2 + CHALLENGE_LEN;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
+ "request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_MD5;
+ *pos++ = CHALLENGE_LEN;
+ memcpy(pos, data->challenge, CHALLENGE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", pos, CHALLENGE_LEN);
+
+ data->state = CONTINUE;
+
+ return (u8 *) req;
+}
+
+
+static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_MD5 ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
+ return TRUE;
+ }
+ pos++;
+ if (*pos != MD5_MAC_LEN ||
+ sizeof(*resp) + 2 + MD5_MAC_LEN > len) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
+ "(response_len=%d respDataLen=%lu",
+ *pos, (unsigned long) respDataLen);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_md5_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_md5_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos;
+ MD5_CTX context;
+ u8 hash[MD5_MAC_LEN];
+
+ if (sm->user == NULL || sm->user->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+ data->state = FAILURE;
+ return;
+ }
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos += 2; /* Skip type and len */
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
+
+ MD5Init(&context);
+ MD5Update(&context, &resp->identifier, 1);
+ MD5Update(&context, sm->user->password, sm->user->password_len);
+ MD5Update(&context, data->challenge, CHALLENGE_LEN);
+ MD5Final(hash, &context);
+
+ if (memcmp(hash, pos, MD5_MAC_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
+ data->state = SUCCESS;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure");
+ data->state = FAILURE;
+ }
+}
+
+
+static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_md5_data *data = priv;
+ return data->state != CONTINUE;
+}
+
+
+static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_md5_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_md5 =
+{
+ .method = EAP_TYPE_MD5,
+ .name = "MD5",
+ .init = eap_md5_init,
+ .reset = eap_md5_reset,
+ .buildReq = eap_md5_buildReq,
+ .check = eap_md5_check,
+ .process = eap_md5_process,
+ .isDone = eap_md5_isDone,
+ .isSuccess = eap_md5_isSuccess,
+};
diff --git a/contrib/hostapd/eap_mschapv2.c b/contrib/hostapd/eap_mschapv2.c
new file mode 100644
index 000000000000..5cbf6eb71289
--- /dev/null
+++ b/contrib/hostapd/eap_mschapv2.c
@@ -0,0 +1,483 @@
+/*
+ * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "ms_funcs.h"
+
+
+struct eap_mschapv2_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_MSCHAPV2 */
+ u8 op_code; /* MSCHAPV2_OP_* */
+ u8 mschapv2_id; /* must be changed for challenges, but not for
+ * success/failure */
+ u8 ms_length[2]; /* Note: misaligned; length - 5 */
+ /* followed by data */
+} __attribute__ ((packed));
+
+#define MSCHAPV2_OP_CHALLENGE 1
+#define MSCHAPV2_OP_RESPONSE 2
+#define MSCHAPV2_OP_SUCCESS 3
+#define MSCHAPV2_OP_FAILURE 4
+#define MSCHAPV2_OP_CHANGE_PASSWORD 7
+
+#define MSCHAPV2_RESP_LEN 49
+
+#define ERROR_RESTRICTED_LOGON_HOURS 646
+#define ERROR_ACCT_DISABLED 647
+#define ERROR_PASSWD_EXPIRED 648
+#define ERROR_NO_DIALIN_PERMISSION 649
+#define ERROR_AUTHENTICATION_FAILURE 691
+#define ERROR_CHANGING_PASSWORD 709
+
+#define PASSWD_CHANGE_CHAL_LEN 16
+
+
+#define CHALLENGE_LEN 16
+
+struct eap_mschapv2_data {
+ u8 auth_challenge[CHALLENGE_LEN];
+ u8 auth_response[20];
+ enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
+ u8 resp_mschapv2_id;
+};
+
+
+static void * eap_mschapv2_init(struct eap_sm *sm)
+{
+ struct eap_mschapv2_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = CHALLENGE;
+
+ return data;
+}
+
+
+static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_mschapv2_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_mschapv2_build_challenge(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_mschapv2_hdr *req;
+ u8 *pos;
+ char *name = "hostapd"; /* TODO: make this configurable */
+
+ if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
+ "data");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ *reqDataLen = sizeof(*req) + 1 + CHALLENGE_LEN + strlen(name);
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+ " for request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ req->type = EAP_TYPE_MSCHAPV2;
+ req->op_code = MSCHAPV2_OP_CHALLENGE;
+ req->mschapv2_id = id;
+ req->ms_length[0] = (*reqDataLen - 5) >> 8;
+ req->ms_length[1] = (*reqDataLen - 5) & 0xff;
+ pos = (u8 *) (req + 1);
+ *pos++ = CHALLENGE_LEN;
+ memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos,
+ CHALLENGE_LEN);
+ pos += CHALLENGE_LEN;
+ memcpy(pos, name, strlen(name));
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_mschapv2_build_success_req(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_mschapv2_hdr *req;
+ u8 *pos, *msg, *end;
+ char *message = "OK";
+ size_t msg_len;
+ int i;
+
+ msg_len = 2 + 2 * sizeof(data->auth_response) + 3 + strlen(message);
+ *reqDataLen = sizeof(*req) + msg_len;
+ req = malloc(*reqDataLen + 1);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+ " for request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ req->type = EAP_TYPE_MSCHAPV2;
+ req->op_code = MSCHAPV2_OP_SUCCESS;
+ req->mschapv2_id = data->resp_mschapv2_id;
+ req->ms_length[0] = (*reqDataLen - 5) >> 8;
+ req->ms_length[1] = (*reqDataLen - 5) & 0xff;
+
+ msg = pos = (u8 *) (req + 1);
+ end = ((u8 *) req) + *reqDataLen + 1;
+
+ pos += snprintf((char *) pos, end - pos, "S=");
+ for (i = 0; i < sizeof(data->auth_response); i++) {
+ pos += snprintf((char *) pos, end - pos, "%02X",
+ data->auth_response[i]);
+ }
+ pos += snprintf((char *) pos, end - pos, " M=%s", message);
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
+ msg, msg_len);
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_mschapv2_build_failure_req(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_mschapv2_hdr *req;
+ u8 *pos;
+ char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
+ "M=FAILED";
+ size_t msg_len;
+
+ msg_len = strlen(message);
+ *reqDataLen = sizeof(*req) + msg_len;
+ req = malloc(*reqDataLen + 1);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
+ " for request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ req->type = EAP_TYPE_MSCHAPV2;
+ req->op_code = MSCHAPV2_OP_FAILURE;
+ req->mschapv2_id = data->resp_mschapv2_id;
+ req->ms_length[0] = (*reqDataLen - 5) >> 8;
+ req->ms_length[1] = (*reqDataLen - 5) & 0xff;
+
+ pos = (u8 *) (req + 1);
+ memcpy(pos, message, msg_len);
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
+ (u8 *) message, msg_len);
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_mschapv2_data *data = priv;
+
+ switch (data->state) {
+ case CHALLENGE:
+ return eap_mschapv2_build_challenge(sm, data, id, reqDataLen);
+ case SUCCESS_REQ:
+ return eap_mschapv2_build_success_req(sm, data, id,
+ reqDataLen);
+ case FAILURE_REQ:
+ return eap_mschapv2_build_failure_req(sm, data, id,
+ reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
+ "buildReq", data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_mschapv2_data *data = priv;
+ struct eap_mschapv2_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_mschapv2_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < 6 || resp->type != EAP_TYPE_MSCHAPV2 ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
+ return TRUE;
+ }
+
+ if (data->state == CHALLENGE &&
+ resp->op_code != MSCHAPV2_OP_RESPONSE) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
+ "ignore op %d", resp->op_code);
+ return TRUE;
+ }
+
+ if (data->state == SUCCESS_REQ &&
+ resp->op_code != MSCHAPV2_OP_SUCCESS &&
+ resp->op_code != MSCHAPV2_OP_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
+ "Failure - ignore op %d", resp->op_code);
+ return TRUE;
+ }
+
+ if (data->state == FAILURE_REQ &&
+ resp->op_code != MSCHAPV2_OP_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
+ "- ignore op %d", resp->op_code);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_mschapv2_process_response(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_mschapv2_hdr *resp;
+ u8 *pos;
+ u8 *peer_challenge, *nt_response, flags, *name;
+ size_t name_len;
+ u8 expected[24];
+ int i;
+ u8 *username, *user;
+ size_t username_len, user_len;
+
+ resp = (struct eap_mschapv2_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+
+ if (respDataLen < sizeof(resp) + 1 + 49 ||
+ resp->op_code != MSCHAPV2_OP_RESPONSE ||
+ pos[0] != 49) {
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
+ respData, respDataLen);
+ data->state = FAILURE;
+ return;
+ }
+ data->resp_mschapv2_id = resp->mschapv2_id;
+ pos++;
+ peer_challenge = pos;
+ pos += 16 + 8;
+ nt_response = pos;
+ pos += 24;
+ flags = *pos++;
+ name = pos;
+ name_len = respData + respDataLen - name;
+
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
+ peer_challenge, 16);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
+ wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
+
+ /* MSCHAPv2 does not include optional domain name in the
+ * challenge-response calculation, so remove domain prefix
+ * (if present). */
+ username = sm->identity;
+ username_len = sm->identity_len;
+ for (i = 0; i < username_len; i++) {
+ if (username[i] == '\\') {
+ username_len -= i + 1;
+ username += i + 1;
+ break;
+ }
+ }
+
+ user = name;
+ user_len = name_len;
+ for (i = 0; i < user_len; i++) {
+ if (user[i] == '\\') {
+ user_len -= i + 1;
+ user += i + 1;
+ break;
+ }
+ }
+
+ if (username_len != user_len ||
+ memcmp(username, user, username_len) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
+ "name", username, username_len);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
+ "name", user, user_len);
+ data->state = FAILURE;
+ return;
+ }
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
+ username, username_len);
+
+ generate_nt_response(data->auth_challenge, peer_challenge,
+ username, username_len,
+ sm->user->password, sm->user->password_len,
+ expected);
+
+ if (memcmp(nt_response, expected, 24) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
+ data->state = SUCCESS_REQ;
+
+
+ /* Authenticator response is not really needed yet, but
+ * calculate it here so that peer_challenge and username need
+ * not be saved. */
+ generate_authenticator_response(sm->user->password,
+ sm->user->password_len,
+ peer_challenge,
+ data->auth_challenge,
+ username, username_len,
+ nt_response,
+ data->auth_response);
+ } else {
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
+ expected, 24);
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
+ data->state = FAILURE_REQ;
+ }
+}
+
+
+static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_mschapv2_hdr *resp;
+
+ resp = (struct eap_mschapv2_hdr *) respData;
+
+ if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
+ " - authentication completed successfully");
+ data->state = SUCCESS;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
+ "Response - peer rejected authentication");
+ data->state = FAILURE;
+ }
+}
+
+
+static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
+ struct eap_mschapv2_data *data,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_mschapv2_hdr *resp;
+
+ resp = (struct eap_mschapv2_hdr *) respData;
+
+ if (resp->op_code == MSCHAPV2_OP_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
+ " - authentication failed");
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
+ "Response - authentication failed");
+ }
+
+ data->state = FAILURE;
+}
+
+
+static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_mschapv2_data *data = priv;
+
+ if (sm->user == NULL || sm->user->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+ data->state = FAILURE;
+ return;
+ }
+
+ switch (data->state) {
+ case CHALLENGE:
+ eap_mschapv2_process_response(sm, data, respData, respDataLen);
+ break;
+ case SUCCESS_REQ:
+ eap_mschapv2_process_success_resp(sm, data, respData,
+ respDataLen);
+ break;
+ case FAILURE_REQ:
+ eap_mschapv2_process_failure_resp(sm, data, respData,
+ respDataLen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
+ "process", data->state);
+ break;
+ }
+}
+
+
+static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_mschapv2_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_mschapv2_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_mschapv2 =
+{
+ .method = EAP_TYPE_MSCHAPV2,
+ .name = "MSCHAPV2",
+ .init = eap_mschapv2_init,
+ .reset = eap_mschapv2_reset,
+ .buildReq = eap_mschapv2_buildReq,
+ .check = eap_mschapv2_check,
+ .process = eap_mschapv2_process,
+ .isDone = eap_mschapv2_isDone,
+ .isSuccess = eap_mschapv2_isSuccess,
+};
diff --git a/contrib/hostapd/eap_peap.c b/contrib/hostapd/eap_peap.c
new file mode 100644
index 000000000000..aa91976e777a
--- /dev/null
+++ b/contrib/hostapd/eap_peap.c
@@ -0,0 +1,720 @@
+/*
+ * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "tls.h"
+
+
+/* Maximum supported PEAP version
+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
+ * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
+ */
+#define EAP_PEAP_VERSION 1
+
+
+static void eap_peap_reset(struct eap_sm *sm, void *priv);
+
+
+struct eap_peap_data {
+ struct eap_ssl_data ssl;
+ enum {
+ START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
+ PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
+ } state;
+
+ int peap_version;
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int force_version;
+};
+
+
+static const char * eap_peap_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case PHASE1:
+ return "PHASE1";
+ case PHASE2_START:
+ return "PHASE2_START";
+ case PHASE2_ID:
+ return "PHASE2_ID";
+ case PHASE2_METHOD:
+ return "PHASE2_METHOD";
+ case PHASE2_TLV:
+ return "PHASE2_TLV";
+ case SUCCESS_REQ:
+ return "SUCCESS_REQ";
+ case FAILURE_REQ:
+ return "FAILURE_REQ";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_peap_state(struct eap_peap_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
+ eap_peap_state_txt(data->state),
+ eap_peap_state_txt(state));
+ data->state = state;
+}
+
+
+static EapType eap_peap_req_success(struct eap_sm *sm,
+ struct eap_peap_data *data)
+{
+ if (data->state == FAILURE || data->state == FAILURE_REQ) {
+ eap_peap_state(data, FAILURE);
+ return EAP_TYPE_NONE;
+ }
+
+ if (data->peap_version == 0) {
+ sm->tlv_request = TLV_REQ_SUCCESS;
+ eap_peap_state(data, PHASE2_TLV);
+ return EAP_TYPE_TLV;
+ } else {
+ eap_peap_state(data, SUCCESS_REQ);
+ return EAP_TYPE_NONE;
+ }
+}
+
+
+static EapType eap_peap_req_failure(struct eap_sm *sm,
+ struct eap_peap_data *data)
+{
+ if (data->state == FAILURE || data->state == FAILURE_REQ ||
+ data->state == SUCCESS_REQ ||
+ (data->phase2_method &&
+ data->phase2_method->method == EAP_TYPE_TLV)) {
+ eap_peap_state(data, FAILURE);
+ return EAP_TYPE_NONE;
+ }
+
+ if (data->peap_version == 0) {
+ sm->tlv_request = TLV_REQ_FAILURE;
+ eap_peap_state(data, PHASE2_TLV);
+ return EAP_TYPE_TLV;
+ } else {
+ eap_peap_state(data, FAILURE_REQ);
+ return EAP_TYPE_NONE;
+ }
+}
+
+
+static void * eap_peap_init(struct eap_sm *sm)
+{
+ struct eap_peap_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->peap_version = EAP_PEAP_VERSION;
+ data->force_version = -1;
+ if (sm->user && sm->user->force_version >= 0) {
+ data->force_version = sm->user->force_version;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
+ data->force_version);
+ data->peap_version = data->force_version;
+ }
+ data->state = START;
+
+ if (eap_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
+ eap_peap_reset(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_peap_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->reset(sm, data->phase2_priv);
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ free(data);
+}
+
+
+static u8 * eap_peap_build_start(struct eap_sm *sm, struct eap_peap_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+
+ *reqDataLen = sizeof(*req) + 2;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
+ " request");
+ eap_peap_state(data, FAILURE);
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_PEAP;
+ *pos = EAP_TLS_FLAGS_START | data->peap_version;
+
+ eap_peap_state(data, PHASE1);
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_peap_build_req(struct eap_sm *sm, struct eap_peap_data *data,
+ int id, size_t *reqDataLen)
+{
+ int res;
+ u8 *req;
+
+ res = eap_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id, &req,
+ reqDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, starting "
+ "Phase2");
+ eap_peap_state(data, PHASE2_START);
+ }
+
+ if (res == 1)
+ return eap_tls_build_ack(reqDataLen, id, EAP_TYPE_PEAP,
+ data->peap_version);
+ return req;
+}
+
+
+static u8 * eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
+ int id, u8 *plain, size_t plain_len,
+ size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *req;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented. */
+ req = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (req == NULL)
+ return NULL;
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_PEAP;
+ *pos++ = data->peap_version;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
+ "data");
+ free(req);
+ return NULL;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ req->length = host_to_be16(*out_len);
+ return (u8 *) req;
+}
+
+
+static u8 * eap_peap_build_phase2_req(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *req, *buf, *encr_req;
+ size_t req_len;
+
+ buf = req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
+ &req_len);
+ if (req == NULL)
+ return NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
+ req, req_len);
+
+ if (data->peap_version == 0 &&
+ data->phase2_method->method != EAP_TYPE_TLV) {
+ req += sizeof(struct eap_hdr);
+ req_len -= sizeof(struct eap_hdr);
+ }
+
+ encr_req = eap_peap_encrypt(sm, data, id, req, req_len, reqDataLen);
+ free(buf);
+
+ return encr_req;
+}
+
+
+static u8 * eap_peap_build_phase2_term(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ int id, size_t *reqDataLen, int success)
+{
+ u8 *encr_req;
+ size_t req_len;
+ struct eap_hdr *hdr;
+
+ req_len = sizeof(*hdr);
+ hdr = malloc(req_len);
+ if (hdr == NULL) {
+ return NULL;
+ }
+
+ memset(hdr, 0, req_len);
+ hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
+ hdr->identifier = id;
+ hdr->length = htons(req_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
+ (u8 *) hdr, req_len);
+
+ encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len,
+ reqDataLen);
+ free(hdr);
+
+ return encr_req;
+}
+
+
+static u8 * eap_peap_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_peap_data *data = priv;
+
+ switch (data->state) {
+ case START:
+ return eap_peap_build_start(sm, data, id, reqDataLen);
+ case PHASE1:
+ return eap_peap_build_req(sm, data, id, reqDataLen);
+ case PHASE2_ID:
+ case PHASE2_METHOD:
+ case PHASE2_TLV:
+ return eap_peap_build_phase2_req(sm, data, id, reqDataLen);
+ case SUCCESS_REQ:
+ return eap_peap_build_phase2_term(sm, data, id, reqDataLen, 1);
+ case FAILURE_REQ:
+ return eap_peap_build_phase2_term(sm, data, id, reqDataLen, 0);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
+ __func__, data->state);
+ return NULL;
+ }
+}
+
+
+static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_PEAP ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
+ u8 eap_type)
+{
+ if (data->phase2_priv && data->phase2_method) {
+ data->phase2_method->reset(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ }
+ data->phase2_method = eap_sm_get_eap_methods(eap_type);
+ if (!data->phase2_method)
+ return -1;
+
+ sm->init_phase2 = 1;
+ data->phase2_priv = data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+ return 0;
+}
+
+
+static void eap_peap_process_phase2_response(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ u8 *in_data, size_t in_len)
+{
+ u8 next_type = EAP_TYPE_NONE;
+ struct eap_hdr *hdr;
+ u8 *pos;
+ size_t left;
+
+ if (data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
+ "initialized?!", __func__);
+ return;
+ }
+
+ hdr = (struct eap_hdr *) in_data;
+ pos = (u8 *) (hdr + 1);
+ left = in_len - sizeof(*hdr);
+
+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
+ "allowed types", pos + 1, left - 1);
+ eap_sm_process_nak(sm, pos + 1, left - 1);
+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index] !=
+ EAP_TYPE_NONE) {
+ next_type =
+ sm->user->methods[sm->user_eap_method_index++];
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
+ next_type);
+ } else {
+ next_type = eap_peap_req_failure(sm, data);
+ }
+ eap_peap_phase2_init(sm, data, next_type);
+ return;
+ }
+
+ if (data->phase2_method->check(sm, data->phase2_priv, in_data,
+ in_len)) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
+ "ignore the packet");
+ return;
+ }
+
+ data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
+
+ if (!data->phase2_method->isDone(sm, data->phase2_priv))
+ return;
+
+
+ if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
+ next_type = eap_peap_req_failure(sm, data);
+ eap_peap_phase2_init(sm, data, next_type);
+ return;
+ }
+
+ switch (data->state) {
+ case PHASE2_ID:
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
+ "Identity not found in the user "
+ "database",
+ sm->identity, sm->identity_len);
+ next_type = eap_peap_req_failure(sm, data);
+ break;
+ }
+
+ eap_peap_state(data, PHASE2_METHOD);
+ next_type = sm->user->methods[0];
+ sm->user_eap_method_index = 1;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+ break;
+ case PHASE2_METHOD:
+ next_type = eap_peap_req_success(sm, data);
+ break;
+ case PHASE2_TLV:
+ if (sm->tlv_request == TLV_REQ_SUCCESS ||
+ data->state == SUCCESS_REQ) {
+ eap_peap_state(data, SUCCESS);
+ } else {
+ eap_peap_state(data, FAILURE);
+ }
+ break;
+ case FAILURE:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
+ __func__, data->state);
+ break;
+ }
+
+ eap_peap_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_peap_process_phase2(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct eap_hdr *resp,
+ u8 *in_data, size_t in_len)
+{
+ u8 *in_decrypted;
+ int buf_len, len_decrypted, len, res;
+ struct eap_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
+ " Phase 2", (unsigned long) in_len);
+
+ res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
+ if (res < 0 || res == 1)
+ return;
+
+ buf_len = in_len;
+ if (data->ssl.tls_in_total > buf_len)
+ buf_len = data->ssl.tls_in_total;
+ in_decrypted = malloc(buf_len);
+ if (in_decrypted == NULL) {
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
+ "for decryption");
+ return;
+ }
+
+ len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_data, in_len,
+ in_decrypted, buf_len);
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ if (len_decrypted < 0) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
+ "data");
+ free(in_decrypted);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
+ in_decrypted, len_decrypted);
+
+ hdr = (struct eap_hdr *) in_decrypted;
+
+ if (data->peap_version == 0 && data->state != PHASE2_TLV) {
+ struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
+ len_decrypted);
+ if (nhdr == NULL) {
+ free(in_decrypted);
+ return;
+ }
+ memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
+ free(in_decrypted);
+ nhdr->code = resp->code;
+ nhdr->identifier = resp->identifier;
+ nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
+ len_decrypted);
+
+ len_decrypted += sizeof(struct eap_hdr);
+ in_decrypted = (u8 *) nhdr;
+ }
+ hdr = (struct eap_hdr *) in_decrypted;
+ if (len_decrypted < sizeof(*hdr)) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
+ "EAP frame (len=%d)", len_decrypted);
+ eap_peap_req_failure(sm, data);
+ return;
+ }
+ len = be_to_host16(hdr->length);
+ if (len > len_decrypted) {
+ free(in_decrypted);
+ wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
+ "Phase 2 EAP frame (len=%d hdr->length=%d)",
+ len_decrypted, len);
+ eap_peap_req_failure(sm, data);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
+ "identifier=%d length=%d", hdr->code, hdr->identifier, len);
+ switch (hdr->code) {
+ case EAP_CODE_RESPONSE:
+ eap_peap_process_phase2_response(sm, data, (u8 *) hdr, len);
+ break;
+ case EAP_CODE_SUCCESS:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
+ if (data->state == SUCCESS_REQ) {
+ eap_peap_state(data, SUCCESS);
+ }
+ break;
+ case EAP_CODE_FAILURE:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
+ eap_peap_state(data, FAILURE);
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
+ "Phase 2 EAP header", hdr->code);
+ break;
+ }
+
+ free(in_decrypted);
+ }
+
+
+static void eap_peap_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_peap_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, flags;
+ int left;
+ unsigned int tls_msg_len;
+ int peer_version;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ flags = *pos++;
+ left = htons(resp->length) - sizeof(struct eap_hdr) - 2;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) respDataLen, flags);
+ peer_version = flags & EAP_PEAP_VERSION_MASK;
+ if (data->force_version >= 0 && peer_version != data->force_version) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
+ " version (forced=%d peer=%d) - reject",
+ data->force_version, peer_version);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ if (peer_version < data->peap_version) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
+ "use version %d",
+ peer_version, data->peap_version, peer_version);
+ data->peap_version = peer_version;
+
+ }
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
+ "length");
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ switch (data->state) {
+ case PHASE1:
+ if (eap_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
+ "failed");
+ eap_peap_state(data, FAILURE);
+ }
+ break;
+ case PHASE2_START:
+ eap_peap_state(data, PHASE2_ID);
+ eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+ break;
+ case PHASE2_ID:
+ case PHASE2_METHOD:
+ case PHASE2_TLV:
+ eap_peap_process_phase2(sm, data, resp, pos, left);
+ break;
+ case SUCCESS_REQ:
+ eap_peap_state(data, SUCCESS);
+ break;
+ case FAILURE_REQ:
+ eap_peap_state(data, FAILURE);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
+ data->state, __func__);
+ break;
+ }
+}
+
+
+static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ /* TODO: PEAPv1 - different label in some cases */
+ eapKeyData = eap_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-PEAP: Derived key",
+ eapKeyData, EAP_TLS_KEY_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
+ }
+
+ return eapKeyData;
+}
+
+
+static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_peap_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_peap =
+{
+ .method = EAP_TYPE_PEAP,
+ .name = "PEAP",
+ .init = eap_peap_init,
+ .reset = eap_peap_reset,
+ .buildReq = eap_peap_buildReq,
+ .check = eap_peap_check,
+ .process = eap_peap_process,
+ .isDone = eap_peap_isDone,
+ .getKey = eap_peap_getKey,
+ .isSuccess = eap_peap_isSuccess,
+};
diff --git a/contrib/hostapd/eap_sim.c b/contrib/hostapd/eap_sim.c
new file mode 100644
index 000000000000..aade18161d1d
--- /dev/null
+++ b/contrib/hostapd/eap_sim.c
@@ -0,0 +1,431 @@
+/*
+ * hostapd / EAP-SIM (draft-haverinen-pppext-eap-sim-15.txt)
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "sha1.h"
+#include "eap_i.h"
+#include "eap_sim_common.h"
+#include "eap_sim_db.h"
+
+
+#define EAP_SIM_VERSION 1
+
+/* EAP-SIM Subtypes */
+#define EAP_SIM_SUBTYPE_START 10
+#define EAP_SIM_SUBTYPE_CHALLENGE 11
+#define EAP_SIM_SUBTYPE_NOTIFICATION 12
+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
+#define EAP_SIM_UNSUPPORTED_VERSION 1
+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
+#define EAP_SIM_RAND_NOT_FRESH 3
+
+#define KC_LEN 8
+#define SRES_LEN 4
+#define EAP_SIM_MAX_FAST_REAUTHS 1000
+
+#define EAP_SIM_MAX_CHAL 3
+
+struct eap_sim_data {
+ u8 mk[EAP_SIM_MK_LEN];
+ u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
+ u8 k_aut[EAP_SIM_K_AUT_LEN];
+ u8 k_encr[EAP_SIM_K_ENCR_LEN];
+ u8 msk[EAP_SIM_KEYING_DATA_LEN];
+ u8 kc[EAP_SIM_MAX_CHAL][KC_LEN];
+ u8 sres[EAP_SIM_MAX_CHAL][SRES_LEN];
+ u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+ int num_chal;
+ enum { START, CHALLENGE, SUCCESS, FAILURE } state;
+};
+
+
+static const char * eap_sim_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case CHALLENGE:
+ return "CHALLENGE";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_sim_state(struct eap_sim_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM %s -> %s",
+ eap_sim_state_txt(data->state),
+ eap_sim_state_txt(state));
+ data->state = state;
+}
+
+
+static void * eap_sim_init(struct eap_sm *sm)
+{
+ struct eap_sim_data *data;
+
+ if (sm->eap_sim_db_priv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
+ return NULL;
+ }
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = START;
+
+ return data;
+}
+
+
+static void eap_sim_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+ u8 ver[2];
+
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+ EAP_SIM_SUBTYPE_START);
+ if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len)) {
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+ }
+ ver[0] = 0;
+ ver[1] = EAP_SIM_VERSION;
+ eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
+ ver, sizeof(ver));
+ return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_sim_build_challenge(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+ EAP_SIM_SUBTYPE_CHALLENGE);
+ eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
+ data->num_chal * GSM_RAND_LEN);
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+}
+
+
+static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_sim_data *data = priv;
+
+ switch (data->state) {
+ case START:
+ return eap_sim_build_start(sm, data, id, reqDataLen);
+ case CHALLENGE:
+ return eap_sim_build_challenge(sm, data, id, reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
+ "buildReq", data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_sim_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, subtype;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
+ return TRUE;
+ }
+ subtype = pos[1];
+
+ if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
+ return FALSE;
+
+ switch (data->state) {
+ case START:
+ if (subtype != EAP_SIM_SUBTYPE_START) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ case CHALLENGE:
+ if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
+ "processing a response", data->state);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
+{
+ return version == EAP_SIM_VERSION;
+}
+
+
+static void eap_sim_derive_mk(struct eap_sim_data *data,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_mt, int selected_version,
+ int num_chal, const u8 *kc)
+{
+ u8 sel_ver[2], ver_list[2];
+ const unsigned char *addr[5];
+ size_t len[5];
+
+ addr[0] = identity;
+ addr[1] = kc;
+ addr[2] = nonce_mt;
+ addr[3] = ver_list;
+ addr[4] = sel_ver;
+
+ len[0] = identity_len;
+ len[1] = num_chal * KC_LEN;
+ len[2] = EAP_SIM_NONCE_MT_LEN;
+ len[3] = sizeof(ver_list);
+ len[4] = sizeof(sel_ver);
+
+ ver_list[0] = 0;
+ ver_list[1] = EAP_SIM_VERSION;
+ sel_ver[0] = selected_version >> 8;
+ sel_ver[1] = selected_version & 0xff;
+
+ /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ sha1_vector(5, addr, len, data->mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
+}
+
+
+static void eap_sim_process_start(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
+
+ if (attr->nonce_mt == NULL || attr->selected_version < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
+ "required attributes");
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ if (!eap_sim_supported_ver(data, attr->selected_version)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
+ "version %d", attr->selected_version);
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ if (attr->identity) {
+ free(sm->identity);
+ sm->identity = malloc(attr->identity_len);
+ if (sm->identity) {
+ memcpy(sm->identity, attr->identity,
+ attr->identity_len);
+ sm->identity_len = attr->identity_len;
+ }
+ }
+
+ if (sm->identity == NULL || sm->identity_len < 1 ||
+ sm->identity[0] != '1') {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
+ " user name");
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
+ sm->identity, sm->identity_len);
+
+ data->num_chal = eap_sim_db_get_gsm_triplets(
+ sm->eap_sim_db_priv, sm->identity, sm->identity_len,
+ EAP_SIM_MAX_CHAL,
+ (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres);
+ if (data->num_chal < 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
+ "authentication triplets for the peer");
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
+ eap_sim_derive_mk(data, sm->identity, sm->identity_len, attr->nonce_mt,
+ attr->selected_version, data->num_chal,
+ (u8 *) data->kc);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+
+ eap_sim_state(data, CHALLENGE);
+}
+
+
+static void eap_sim_process_challenge(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ if (attr->mac == NULL ||
+ eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
+ (u8 *) data->sres, data->num_chal * SRES_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
+ "did not include valid AT_MAC");
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
+ "correct AT_MAC");
+ eap_sim_state(data, SUCCESS);
+}
+
+
+static void eap_sim_process_client_error(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
+ attr->client_error_code);
+ eap_sim_state(data, FAILURE);
+}
+
+
+static void eap_sim_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_sim_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, subtype;
+ size_t len;
+ struct eap_sim_attrs attr;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ subtype = pos[1];
+ len = ntohs(resp->length);
+ pos += 4;
+
+ if (eap_sim_parse_attr(pos, respData + len, &attr, 0, 0)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
+ eap_sim_state(data, FAILURE);
+ return;
+ }
+
+ if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
+ eap_sim_process_client_error(sm, data, respData, len, &attr);
+ return;
+ }
+
+ switch (data->state) {
+ case START:
+ eap_sim_process_start(sm, data, respData, len, &attr);
+ break;
+ case CHALLENGE:
+ eap_sim_process_challenge(sm, data, respData, len, &attr);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
+ "process", data->state);
+ break;
+ }
+}
+
+
+static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+ *len = EAP_SIM_KEYING_DATA_LEN;
+ return key;
+}
+
+
+static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_sim_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_sim =
+{
+ .method = EAP_TYPE_SIM,
+ .name = "SIM",
+ .init = eap_sim_init,
+ .reset = eap_sim_reset,
+ .buildReq = eap_sim_buildReq,
+ .check = eap_sim_check,
+ .process = eap_sim_process,
+ .isDone = eap_sim_isDone,
+ .getKey = eap_sim_getKey,
+ .isSuccess = eap_sim_isSuccess,
+};
diff --git a/contrib/hostapd/eap_sim_common.c b/contrib/hostapd/eap_sim_common.c
new file mode 100644
index 000000000000..98f4fb7d3014
--- /dev/null
+++ b/contrib/hostapd/eap_sim_common.c
@@ -0,0 +1,788 @@
+/*
+ * WPA Supplicant / EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "sha1.h"
+#include "aes_wrap.h"
+#include "eap_sim_common.h"
+
+
+#define MSK_LEN 8
+#define EMSK_LEN 8
+
+
+static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ /* FIPS 186-2 + change notice 1 */
+
+ memcpy(xkey, key, EAP_SIM_MK_LEN);
+ memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_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) */
+ 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]);
+ 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 += SHA1_MAC_LEN;
+ }
+ /* x_j = w_0|w_1 */
+ }
+}
+
+
+void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
+{
+ u8 buf[120], *pos;
+ eap_sim_prf(mk, buf, 120);
+ pos = buf;
+ memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+ pos += EAP_SIM_K_ENCR_LEN;
+ memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+ pos += EAP_SIM_K_AUT_LEN;
+ memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ pos += MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
+ k_encr, EAP_SIM_K_ENCR_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
+ k_aut, EAP_SIM_K_ENCR_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MSK",
+ msk, MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Ext. MSK",
+ msk + MSK_LEN, EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+}
+
+
+void eap_sim_derive_keys_reauth(unsigned int _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk)
+{
+ u8 xkey[SHA1_MAC_LEN];
+ u8 counter[2];
+ const u8 *addr[4];
+ size_t len[4];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = counter;
+ len[1] = 2;
+ addr[2] = nonce_s;
+ len[2] = EAP_SIM_NONCE_S_LEN;
+ addr[3] = mk;
+ len[3] = EAP_SIM_MK_LEN;
+
+ counter[0] = _counter >> 8;
+ counter[1] = _counter & 0xff;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
+ identity, identity_len);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+
+ /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */
+ sha1_vector(4, addr, len, xkey);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
+
+ eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: MSK", msk, MSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Ext. MSK", msk + MSK_LEN, EMSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+}
+
+
+int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
+ u8 *extra, size_t extra_len)
+{
+ unsigned char hmac[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+ u8 rx_mac[EAP_SIM_MAC_LEN];
+
+ if (mac == NULL)
+ return -1;
+
+ addr[0] = req;
+ len[0] = req_len;
+ addr[1] = extra;
+ len[1] = extra_len;
+
+ /* HMAC-SHA1-128 */
+ memcpy(rx_mac, mac, EAP_SIM_MAC_LEN);
+ memset(mac, 0, EAP_SIM_MAC_LEN);
+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+ memcpy(mac, rx_mac, EAP_SIM_MAC_LEN);
+
+ return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+}
+
+
+void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
+ const u8 *extra, size_t extra_len)
+{
+ unsigned char hmac[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = msg;
+ len[0] = msg_len;
+ addr[1] = extra;
+ len[1] = extra_len;
+
+ /* HMAC-SHA1-128 */
+ memset(mac, 0, EAP_SIM_MAC_LEN);
+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
+ memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+}
+
+
+int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
+ int encr)
+{
+ u8 *pos = start, *apos;
+ size_t alen, plen;
+ int list_len, i;
+
+ memset(attr, 0, sizeof(*attr));
+ attr->id_req = NO_ID_REQ;
+ attr->notification = -1;
+ attr->counter = -1;
+ attr->selected_version = -1;
+ attr->client_error_code = -1;
+
+ while (pos < end) {
+ if (pos + 2 > end) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)");
+ return -1;
+ }
+ wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d",
+ pos[0], pos[1] * 4);
+ if (pos + pos[1] * 4 > end) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow "
+ "(pos=%p len=%d end=%p)",
+ pos, pos[1] * 4, end);
+ return -1;
+ }
+ apos = pos + 2;
+ alen = pos[1] * 4 - 2;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data",
+ apos, alen);
+
+ switch (pos[0]) {
+ case EAP_SIM_AT_RAND:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND");
+ apos += 2;
+ alen -= 2;
+ if ((!aka && (alen % GSM_RAND_LEN)) ||
+ (aka && alen != AKA_RAND_LEN)) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->rand = apos;
+ attr->num_chal = alen / GSM_RAND_LEN;
+ break;
+ case EAP_SIM_AT_AUTN:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN");
+ if (!aka) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: "
+ "Unexpected AT_AUTN");
+ return -1;
+ }
+ apos += 2;
+ alen -= 2;
+ if (alen != AKA_AUTN_LEN) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->autn = apos;
+ break;
+ case EAP_SIM_AT_PADDING:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_PADDING");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING");
+ for (i = 2; i < alen; i++) {
+ if (apos[i] != 0) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) "
+ "AT_PADDING used a non-zero"
+ " padding byte");
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: "
+ "(encr) padding bytes",
+ apos + 2, alen - 2);
+ return -1;
+ }
+ }
+ break;
+ case EAP_SIM_AT_NONCE_MT:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT");
+ if (alen != 2 + EAP_SIM_NONCE_MT_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_NONCE_MT length");
+ return -1;
+ }
+ attr->nonce_mt = apos + 2;
+ break;
+ case EAP_SIM_AT_PERMANENT_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ");
+ attr->id_req = PERMANENT_ID;
+ break;
+ case EAP_SIM_AT_MAC:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC");
+ if (alen != 2 + EAP_SIM_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC "
+ "length");
+ return -1;
+ }
+ attr->mac = apos + 2;
+ break;
+ case EAP_SIM_AT_NOTIFICATION:
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_NOTIFICATION length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->notification = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d",
+ attr->notification);
+ break;
+ case EAP_SIM_AT_ANY_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ");
+ attr->id_req = ANY_ID;
+ break;
+ case EAP_SIM_AT_IDENTITY:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
+ attr->identity = apos + 2;
+ attr->identity_len = alen - 2;
+ break;
+ case EAP_SIM_AT_VERSION_LIST:
+ if (aka) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: "
+ "Unexpected AT_VERSION_LIST");
+ return -1;
+ }
+ list_len = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
+ if (list_len < 2 || list_len > alen - 2) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
+ "AT_VERSION_LIST (list_len=%d "
+ "attr_len=%lu)", list_len,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->version_list = apos + 2;
+ attr->version_list_len = list_len;
+ break;
+ case EAP_SIM_AT_SELECTED_VERSION:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION");
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_SELECTED_VERSION length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->selected_version = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION "
+ "%d", attr->selected_version);
+ break;
+ case EAP_SIM_AT_FULLAUTH_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ");
+ attr->id_req = FULLAUTH_ID;
+ break;
+ case EAP_SIM_AT_COUNTER:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_COUNTER");
+ return -1;
+ }
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_COUNTER (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->counter = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
+ attr->counter);
+ break;
+ case EAP_SIM_AT_NONCE_S:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NONCE_S");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NONCE_S");
+ if (alen != 2 + EAP_SIM_NONCE_S_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_NONCE_S (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->nonce_s = apos + 2;
+ break;
+ case EAP_SIM_AT_CLIENT_ERROR_CODE:
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_CLIENT_ERROR_CODE length %lu",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->client_error_code = apos[0] * 256 + apos[1];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE "
+ "%d", attr->client_error_code);
+ break;
+ case EAP_SIM_AT_IV:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV");
+ if (alen != 2 + EAP_SIM_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV "
+ "length %lu", (unsigned long) alen);
+ return -1;
+ }
+ attr->iv = apos + 2;
+ break;
+ case EAP_SIM_AT_ENCR_DATA:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA");
+ attr->encr_data = apos + 2;
+ attr->encr_data_len = alen - 2;
+ if (attr->encr_data_len % 16) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+ "AT_ENCR_DATA length %lu",
+ (unsigned long)
+ attr->encr_data_len);
+ return -1;
+ }
+ break;
+ case EAP_SIM_AT_NEXT_PSEUDONYM:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NEXT_PSEUDONYM");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NEXT_PSEUDONYM");
+ plen = apos[0] * 256 + apos[1];
+ if (plen > alen - 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+ " AT_NEXT_PSEUDONYM (actual"
+ " len %lu, attr len %lu)",
+ (unsigned long) plen,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->next_pseudonym = pos + 4;
+ attr->next_pseudonym_len = plen;
+ break;
+ case EAP_SIM_AT_NEXT_REAUTH_ID:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_NEXT_REAUTH_ID");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_NEXT_REAUTH_ID");
+ plen = apos[0] * 256 + apos[1];
+ if (plen > alen - 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid"
+ " AT_NEXT_REAUTH_ID (actual"
+ " len %lu, attr len %lu)",
+ (unsigned long) plen,
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->next_reauth_id = pos + 4;
+ attr->next_reauth_id_len = plen;
+ break;
+ default:
+ if (pos[0] < 128) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
+ "non-skippable attribute %d",
+ pos[0]);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable"
+ " attribute %d ignored", pos[0]);
+ break;
+ }
+
+ pos += pos[1] * 4;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully "
+ "(aka=%d encr=%d)", aka, encr);
+
+ return 0;
+}
+
+
+int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
+ const u8 *iv, struct eap_sim_attrs *attr, int aka)
+{
+ if (!iv) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
+ return -1;
+ }
+ aes_128_cbc_decrypt(k_encr, iv, encr_data, encr_data_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
+ encr_data, encr_data_len);
+
+ if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
+ aka, 1)) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
+ "decrypted AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+#define EAP_SIM_INIT_LEN 128
+
+struct eap_sim_msg {
+ u8 *buf;
+ size_t buf_len, used;
+ size_t mac, iv, encr; /* index from buf */
+};
+
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
+{
+ struct eap_sim_msg *msg;
+ struct eap_hdr *eap;
+ u8 *pos;
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+ memset(msg, 0, sizeof(*msg));
+
+ msg->buf = malloc(EAP_SIM_INIT_LEN);
+ if (msg->buf == NULL) {
+ free(msg);
+ return NULL;
+ }
+ memset(msg->buf, 0, EAP_SIM_INIT_LEN);
+ msg->buf_len = EAP_SIM_INIT_LEN;
+ eap = (struct eap_hdr *) msg->buf;
+ eap->code = code;
+ eap->identifier = id;
+ msg->used = sizeof(*eap);
+
+ pos = (u8 *) (eap + 1);
+ *pos++ = type;
+ *pos++ = subtype;
+ *pos++ = 0; /* Reserved */
+ *pos++ = 0; /* Reserved */
+ msg->used += 4;
+
+ return msg;
+}
+
+
+u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
+ const u8 *extra, size_t extra_len)
+{
+ struct eap_hdr *eap;
+ u8 *buf;
+
+ if (msg == NULL)
+ return NULL;
+
+ eap = (struct eap_hdr *) msg->buf;
+ eap->length = host_to_be16(msg->used);
+
+ if (k_aut && msg->mac) {
+ eap_sim_add_mac(k_aut, msg->buf, msg->used,
+ msg->buf + msg->mac, extra, extra_len);
+ }
+
+ *len = msg->used;
+ buf = msg->buf;
+ free(msg);
+ return buf;
+}
+
+
+void eap_sim_msg_free(struct eap_sim_msg *msg)
+{
+ if (msg) {
+ free(msg->buf);
+ free(msg);
+ }
+}
+
+
+static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
+{
+ if (msg->used + add_len > msg->buf_len) {
+ u8 *nbuf = realloc(msg->buf, msg->used + add_len);
+ if (nbuf == NULL)
+ return -1;
+ msg->buf = nbuf;
+ msg->buf_len = msg->used + add_len;
+ }
+ return 0;
+}
+
+
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+ const u8 *data, size_t len)
+{
+ int attr_len = 2 + len;
+ int pad_len;
+ u8 *start, *pos;
+
+ if (msg == NULL)
+ return NULL;
+
+ pad_len = (4 - attr_len % 4) % 4;
+ attr_len += pad_len;
+ if (eap_sim_msg_resize(msg, attr_len))
+ return NULL;
+ start = pos = msg->buf + msg->used;
+ *pos++ = attr;
+ *pos++ = attr_len / 4;
+ memcpy(pos, data, len);
+ if (pad_len) {
+ pos += len;
+ memset(pos, 0, pad_len);
+ }
+ msg->used += attr_len;
+ return start;
+}
+
+
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
+ const u8 *data, size_t len)
+{
+ int attr_len = 4 + len;
+ int pad_len;
+ u8 *start, *pos;
+
+ if (msg == NULL)
+ return NULL;
+
+ pad_len = (4 - attr_len % 4) % 4;
+ attr_len += pad_len;
+ if (eap_sim_msg_resize(msg, attr_len))
+ return NULL;
+ start = pos = msg->buf + msg->used;
+ *pos++ = attr;
+ *pos++ = attr_len / 4;
+ *pos++ = value >> 8;
+ *pos++ = value & 0xff;
+ if (data)
+ memcpy(pos, data, len);
+ if (pad_len) {
+ pos += len;
+ memset(pos, 0, pad_len);
+ }
+ msg->used += attr_len;
+ return start;
+}
+
+
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr)
+{
+ u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN);
+ if (pos)
+ msg->mac = (pos - msg->buf) + 4;
+ return pos;
+}
+
+
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+ u8 attr_encr)
+{
+ u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN);
+ if (pos == NULL)
+ return -1;
+ msg->iv = (pos - msg->buf) + 4;
+ if (hostapd_get_rand(msg->buf + msg->iv, EAP_SIM_IV_LEN)) {
+ msg->iv = 0;
+ return -1;
+ }
+
+ pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0);
+ if (pos == NULL) {
+ msg->iv = 0;
+ return -1;
+ }
+ msg->encr = pos - msg->buf;
+
+ return 0;
+}
+
+
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
+{
+ size_t encr_len;
+
+ if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+ return -1;
+
+ encr_len = msg->used - msg->encr - 4;
+ if (encr_len % 16) {
+ u8 *pos;
+ int pad_len = 16 - (encr_len % 16);
+ if (pad_len < 4) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: "
+ "eap_sim_msg_add_encr_end - invalid pad_len"
+ " %d", pad_len);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, " *AT_PADDING");
+ pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
+ if (pos == NULL)
+ return -1;
+ memset(pos + 4, 0, pad_len - 4);
+ encr_len += pad_len;
+ }
+ wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
+ (unsigned long) encr_len);
+ msg->buf[msg->encr + 1] = encr_len / 4 + 1;
+ aes_128_cbc_encrypt(k_encr, msg->buf + msg->iv,
+ msg->buf + msg->encr + 4, encr_len);
+
+ return 0;
+}
+
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
+{
+ const char *type = aka ? "AKA" : "SIM";
+
+ switch (notification) {
+ case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
+ wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+ "notification (after authentication)", type);
+ break;
+ case EAP_SIM_TEMPORARILY_DENIED:
+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+ "User has been temporarily denied access to the "
+ "requested service", type);
+ break;
+ case EAP_SIM_NOT_SUBSCRIBED:
+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: "
+ "User has not subscribed to the requested service",
+ type);
+ break;
+ case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH:
+ wpa_printf(MSG_WARNING, "EAP-%s: General failure "
+ "notification (before authentication)", type);
+ break;
+ case EAP_SIM_SUCCESS:
+ wpa_printf(MSG_INFO, "EAP-%s: Successful authentication "
+ "notification", type);
+ break;
+ default:
+ if (notification >= 32768) {
+ wpa_printf(MSG_INFO, "EAP-%s: Unrecognized "
+ "non-failure notification %d",
+ type, notification);
+ } else {
+ wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized "
+ "failure notification %d",
+ type, notification);
+ }
+ }
+}
+
+
+#ifdef TEST_MAIN_EAP_SIM_COMMON
+static int test_eap_sim_prf(void)
+{
+ /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
+ u8 xkey[] = {
+ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6
+ };
+ u8 w[] = {
+ 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
+ 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
+ 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
+ 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
+ 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
+ };
+ u8 buf[40];
+
+ printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
+ eap_sim_prf(xkey, buf, sizeof(buf));
+ if (memcmp(w, buf, sizeof(w) != 0)) {
+ printf("eap_sim_prf failed\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int errors = 0;
+
+ errors += test_eap_sim_prf();
+
+ return errors;
+}
+#endif /* TEST_MAIN_EAP_SIM_COMMON */
diff --git a/contrib/hostapd/eap_sim_common.h b/contrib/hostapd/eap_sim_common.h
new file mode 100644
index 000000000000..c89e04e410b9
--- /dev/null
+++ b/contrib/hostapd/eap_sim_common.h
@@ -0,0 +1,101 @@
+#ifndef EAP_SIM_COMMON_H
+#define EAP_SIM_COMMON_H
+
+#define EAP_SIM_NONCE_S_LEN 16
+#define EAP_SIM_NONCE_MT_LEN 16
+#define EAP_SIM_MAC_LEN 16
+#define EAP_SIM_MK_LEN 20
+#define EAP_SIM_K_AUT_LEN 16
+#define EAP_SIM_K_ENCR_LEN 16
+#define EAP_SIM_KEYING_DATA_LEN 64
+#define EAP_SIM_IV_LEN 16
+
+#define GSM_RAND_LEN 16
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+
+void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
+void eap_sim_derive_keys_reauth(unsigned int _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk);
+int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
+ u8 *extra, size_t extra_len);
+void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
+ const u8 *extra, size_t extra_len);
+
+
+/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
+#define EAP_SIM_AT_RAND 1
+#define EAP_SIM_AT_AUTN 2 /* only AKA */
+#define EAP_SIM_AT_RES 3 /* only AKA, only send */
+#define EAP_SIM_AT_AUTS 4 /* only AKA, only send */
+#define EAP_SIM_AT_PADDING 6 /* only encrypted */
+#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
+#define EAP_SIM_AT_PERMANENT_ID_REQ 10
+#define EAP_SIM_AT_MAC 11
+#define EAP_SIM_AT_NOTIFICATION 12
+#define EAP_SIM_AT_ANY_ID_REQ 13
+#define EAP_SIM_AT_IDENTITY 14 /* only send */
+#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */
+#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */
+#define EAP_SIM_AT_FULLAUTH_ID_REQ 17
+#define EAP_SIM_AT_COUNTER 19 /* only encrypted */
+#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
+#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
+#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
+#define EAP_SIM_AT_IV 129
+#define EAP_SIM_AT_ENCR_DATA 130
+#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
+#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
+#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
+#define EAP_SIM_AT_RESULT_IND 135
+
+/* AT_NOTIFICATION notification code values */
+#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
+#define EAP_SIM_TEMPORARILY_DENIED 1026
+#define EAP_SIM_NOT_SUBSCRIBED 1031
+#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
+#define EAP_SIM_SUCCESS 32768
+
+
+enum eap_sim_id_req {
+ NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
+};
+
+
+struct eap_sim_attrs {
+ u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
+ u8 *next_pseudonym, *next_reauth_id;
+ u8 *nonce_mt, *identity;
+ size_t num_chal, version_list_len, encr_data_len;
+ size_t next_pseudonym_len, next_reauth_id_len, identity_len;
+ enum eap_sim_id_req id_req;
+ int notification, counter, selected_version, client_error_code;
+};
+
+int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr,
+ int aka, int encr);
+int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
+ const u8 *iv, struct eap_sim_attrs *attr, int aka);
+
+
+struct eap_sim_msg;
+
+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
+u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
+ const u8 *extra, size_t extra_len);
+void eap_sim_msg_free(struct eap_sim_msg *msg);
+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
+ const u8 *data, size_t len);
+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr,
+ u16 value, const u8 *data, size_t len);
+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr);
+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
+ u8 attr_encr);
+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
+ int attr_pad);
+
+void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
+
+#endif /* EAP_SIM_COMMON_H */
diff --git a/contrib/hostapd/eap_sim_db.c b/contrib/hostapd/eap_sim_db.c
new file mode 100644
index 000000000000..7f617ce860f1
--- /dev/null
+++ b/contrib/hostapd/eap_sim_db.c
@@ -0,0 +1,242 @@
+/*
+ * hostapd / EAP-SIM database/authenticator gateway
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 database/authentication
+ * gateway interface that is expected to be replaced with an implementation of
+ * SS7 gateway to GSM authentication center (HLR/AuC) or a local
+ * implementation of SIM triplet generator.
+ *
+ * The example implementation here reads 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_sim_common.h"
+#include "eap_sim_db.h"
+
+
+/* TODO: add an alternative callback based version of the interface. This is
+ * needed to work better with the single threaded design of hostapd. For this,
+ * the EAP data has to be stored somewhere and eap_sim_db is given a context
+ * pointer for this and a callback function. The callback function will re-send
+ * the EAP data through normal operations which will eventually end up calling
+ * eap_sim_db_get_gsm_triplets() again for the same user. This time, eap_sim_db
+ * should have the triplets available immediately. */
+
+
+struct eap_sim_db_data {
+ char *fname;
+};
+
+#define KC_LEN 8
+#define SRES_LEN 4
+#define RAND_LEN 16
+
+
+/* Initialize EAP-SIM database/authentication gateway interface.
+ * Returns pointer to a private data structure. */
+void * eap_sim_db_init(const char *config)
+{
+ struct eap_sim_db_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL) {
+ return NULL;
+ }
+
+ memset(data, 0, sizeof(*data));
+ data->fname = strdup(config);
+ if (data->fname == NULL) {
+ free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+/* Deinitialize EAP-SIM database/authentication gateway interface.
+ * priv is the pointer from eap_sim_db_init(). */
+void eap_sim_db_deinit(void *priv)
+{
+ struct eap_sim_db_data *data = priv;
+ free(data->fname);
+ free(data);
+}
+
+
+/* Get GSM triplets for user name identity (identity_len bytes). In most cases,
+ * the user name is '1' | IMSI, i.e., 1 followed by the IMSI in ASCII format.
+ * The identity may also include NAI realm (@realm).
+ * priv is the pointer from eap_sim_db_init().
+ * Returns the number of triplets received (has to be less than or equal to
+ * max_chal) or -1 on error (e.g., user not found). rand, kc, and sres are
+ * pointers to data areas for the triplets. */
+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)
+{
+ struct eap_sim_db_data *data = priv;
+ FILE *f;
+ int count, i;
+ char buf[80], *pos, *next;
+
+ f = fopen(data->fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet "
+ "file '%s'", data->fname);
+ return -1;
+ }
+
+ if (identity_len < 2 || identity[0] != '1') {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
+ identity, identity_len);
+ return -1;
+ }
+ identity++;
+ identity_len--;
+ for (i = 0; i < identity_len; i++) {
+ if (identity[i] == '@') {
+ identity_len = i;
+ break;
+ }
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: get triplets for IMSI",
+ identity, identity_len);
+
+ count = 0;
+ while (count < max_chal && fgets(buf, sizeof(buf), f)) {
+ /* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */
+ buf[sizeof(buf) - 1] = '\0';
+ pos = buf;
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ if (*pos == '\n')
+ *pos = '\0';
+ if (pos - buf < 60 || pos[0] == '#')
+ continue;
+
+ pos = strchr(buf, ':');
+ if (pos == NULL)
+ continue;
+ *pos++ = '\0';
+ if (strlen(buf) != identity_len ||
+ memcmp(buf, identity, identity_len) != 0)
+ continue;
+
+ next = strchr(pos, ':');
+ if (next == NULL)
+ continue;
+ *next++ = '\0';
+ if (hexstr2bin(pos, &kc[count * KC_LEN], KC_LEN) < 0)
+ continue;
+
+ pos = next;
+ next = strchr(pos, ':');
+ if (next == NULL)
+ continue;
+ *next++ = '\0';
+ if (hexstr2bin(pos, &sres[count * SRES_LEN], SRES_LEN) < 0)
+ continue;
+
+ if (hexstr2bin(next, &rand[count * RAND_LEN], RAND_LEN) < 0)
+ continue;
+
+ count++;
+ }
+
+ fclose(f);
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: no triplets found");
+ count = -1;
+ }
+
+ return count;
+}
+
+
+/* Verify whether the given user identity (identity_len bytes) is known. In
+ * most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
+ * ASCII format.
+ * priv is the pointer from eap_sim_db_init().
+ * Returns 0 if the user is found and GSM triplets would be available for it or
+ * -1 on error (e.g., user not found or no triplets available). */
+int eap_sim_db_identity_known(void *priv, const u8 *identity,
+ size_t identity_len)
+{
+ struct eap_sim_db_data *data = priv;
+ FILE *f;
+ char buf[80], *pos;
+ int i;
+
+ if (identity_len < 1 || identity[0] != '1') {
+ return -1;
+ }
+
+ f = fopen(data->fname, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet "
+ "file '%s'", data->fname);
+ return -1;
+ }
+
+ if (identity_len < 2 || identity[0] != '1') {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
+ identity, identity_len);
+ return -1;
+ }
+ identity++;
+ identity_len--;
+ for (i = 0; i < identity_len; i++) {
+ if (identity[i] == '@') {
+ identity_len = i;
+ break;
+ }
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ /* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */
+ buf[sizeof(buf) - 1] = '\0';
+ pos = buf;
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ if (*pos == '\n')
+ *pos = '\0';
+ if (pos - buf < 60 || pos[0] == '#')
+ continue;
+
+ pos = strchr(buf, ':');
+ if (pos == NULL)
+ continue;
+ *pos++ = '\0';
+ if (strlen(buf) != identity_len ||
+ memcmp(buf, identity, identity_len) != 0)
+ continue;
+
+ fclose(f);
+ return 0;
+ }
+
+ /* IMSI not found */
+
+ fclose(f);
+ return -1;
+}
diff --git a/contrib/hostapd/eap_sim_db.h b/contrib/hostapd/eap_sim_db.h
new file mode 100644
index 000000000000..57a9871073e2
--- /dev/null
+++ b/contrib/hostapd/eap_sim_db.h
@@ -0,0 +1,44 @@
+#ifndef EAP_SIM_DB_H
+#define EAP_SIM_DB_H
+
+#ifdef EAP_SIM
+
+/* Initialize EAP-SIM database/authentication gateway interface.
+ * Returns pointer to a private data structure. */
+void * eap_sim_db_init(const char *config);
+
+/* Deinitialize EAP-SIM database/authentication gateway interface.
+ * priv is the pointer from eap_sim_db_init(). */
+void eap_sim_db_deinit(void *priv);
+
+/* Get GSM triplets for user name identity (identity_len bytes). In most cases,
+ * the user name is '1' | IMSI, i.e., 1 followed by the IMSI in ASCII format.
+ * priv is the pointer from eap_sim_db_init().
+ * Returns the number of triplets received (has to be less than or equal to
+ * max_chal) or -1 on error (e.g., user not found). rand, kc, and sres are
+ * pointers to data areas for the triplets. */
+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);
+
+/* Verify whether the given user identity (identity_len bytes) is known. In
+ * most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
+ * ASCII format.
+ * priv is the pointer from eap_sim_db_init().
+ * Returns 0 if the user is found and GSM triplets would be available for it or
+ * -1 on error (e.g., user not found or no triplets available). */
+int eap_sim_db_identity_known(void *priv, const u8 *identity,
+ size_t identity_len);
+
+#else /* EAP_SIM */
+static inline void * eap_sim_db_init(const char *config)
+{
+ return NULL;
+}
+
+static inline void eap_sim_db_deinit(void *priv)
+{
+}
+#endif /* EAP_SIM */
+
+#endif /* EAP_SIM_DB_H */
diff --git a/contrib/hostapd/eap_tls.c b/contrib/hostapd/eap_tls.c
new file mode 100644
index 000000000000..58ab2776a83c
--- /dev/null
+++ b/contrib/hostapd/eap_tls.c
@@ -0,0 +1,246 @@
+/*
+ * hostapd / EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "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;
+};
+
+
+static void * eap_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = START;
+
+ if (eap_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_tls_ssl_deinit(sm, &data->ssl);
+ free(data);
+}
+
+
+static u8 * eap_tls_build_start(struct eap_sm *sm, struct eap_tls_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+
+ *reqDataLen = sizeof(*req) + 2;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
+ "request");
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_TLS;
+ *pos = EAP_TLS_FLAGS_START;
+
+ data->state = CONTINUE;
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_tls_build_req(struct eap_sm *sm, struct eap_tls_data *data,
+ int id, size_t *reqDataLen)
+{
+ int res;
+ u8 *req;
+
+ res = eap_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
+ &req, reqDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+ data->state = SUCCESS;
+ }
+
+ if (res == 1)
+ return eap_tls_build_ack(reqDataLen, id, EAP_TYPE_TLS, 0);
+ return req;
+}
+
+
+static u8 * eap_tls_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_tls_data *data = priv;
+
+ switch (data->state) {
+ case START:
+ return eap_tls_build_start(sm, data, id, reqDataLen);
+ case CONTINUE:
+ return eap_tls_build_req(sm, data, id, reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
+ __func__, data->state);
+ return NULL;
+ }
+}
+
+
+static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_TLS ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_tls_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_tls_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, flags;
+ int left;
+ unsigned int tls_msg_len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ flags = *pos++;
+ left = htons(resp->length) - sizeof(struct eap_hdr) - 2;
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) respDataLen, flags);
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
+ "length");
+ data->state = FAILURE;
+ return;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ if (eap_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TLS: TLS processing failed");
+ data->state = FAILURE;
+ return;
+ }
+}
+
+
+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_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 Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_tls_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_tls =
+{
+ .method = EAP_TYPE_TLS,
+ .name = "TLS",
+ .init = eap_tls_init,
+ .reset = eap_tls_reset,
+ .buildReq = eap_tls_buildReq,
+ .check = eap_tls_check,
+ .process = eap_tls_process,
+ .isDone = eap_tls_isDone,
+ .getKey = eap_tls_getKey,
+ .isSuccess = eap_tls_isSuccess,
+};
diff --git a/contrib/hostapd/eap_tls_common.c b/contrib/hostapd/eap_tls_common.c
new file mode 100644
index 000000000000..ca10eca7e46e
--- /dev/null
+++ b/contrib/hostapd/eap_tls_common.c
@@ -0,0 +1,272 @@
+/*
+ * hostapd / EAP-TLS/PEAP/TTLS common functions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "sha1.h"
+#include "tls.h"
+
+
+int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+ int verify_peer)
+{
+ data->eap = sm;
+ data->phase2 = sm->init_phase2;
+
+ data->conn = tls_connection_init(sm->ssl_ctx);
+ if (data->conn == NULL) {
+ wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
+ "connection");
+ return -1;
+ }
+
+ if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
+ NULL)) {
+ wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
+ "of TLS peer certificate");
+ tls_connection_deinit(sm->ssl_ctx, data->conn);
+ data->conn = NULL;
+ return -1;
+ }
+
+ /* TODO: make this configurable */
+ data->tls_out_limit = 1398;
+ if (data->phase2) {
+ /* Limit the fragment size in the inner TLS authentication
+ * since the outer authentication with EAP-PEAP does not yet
+ * support fragmentation */
+ if (data->tls_out_limit > 100)
+ data->tls_out_limit -= 100;
+ }
+ return 0;
+}
+
+
+void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+ tls_connection_deinit(sm->ssl_ctx, data->conn);
+ free(data->tls_in);
+ free(data->tls_out);
+}
+
+
+u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len)
+{
+ struct tls_keys keys;
+ u8 *random;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+ out = malloc(len);
+ random = malloc(keys.client_random_len + keys.server_random_len);
+ if (out == NULL || random == NULL) {
+ free(out);
+ free(random);
+ return NULL;
+ }
+ memcpy(random, keys.client_random, keys.client_random_len);
+ memcpy(random + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ if (tls_prf(keys.master_key, keys.master_key_len,
+ label, random, keys.client_random_len +
+ keys.server_random_len, out, len)) {
+ free(random);
+ free(out);
+ return NULL;
+ }
+ free(random);
+ return out;
+}
+
+
+int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 **in_data, size_t *in_len)
+{
+ u8 *buf;
+
+ if (data->tls_in_left > *in_len || data->tls_in) {
+ buf = realloc(data->tls_in, data->tls_in_len + *in_len);
+ if (buf == NULL) {
+ free(data->tls_in);
+ data->tls_in = NULL;
+ data->tls_in_len = 0;
+ wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
+ "for TLS data");
+ return -1;
+ }
+ memcpy(buf + data->tls_in_len, *in_data, *in_len);
+ data->tls_in = buf;
+ data->tls_in_len += *in_len;
+ if (*in_len > data->tls_in_left) {
+ wpa_printf(MSG_INFO, "SSL: more data than TLS message "
+ "length indicated");
+ data->tls_in_left = 0;
+ return -1;
+ }
+ data->tls_in_left -= *in_len;
+ if (data->tls_in_left > 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
+ "data", (unsigned long) data->tls_in_left);
+ return 1;
+ }
+
+ *in_data = data->tls_in;
+ *in_len = data->tls_in_len;
+ } else
+ data->tls_in_left = 0;
+
+ return 0;
+}
+
+
+int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 *in_data, size_t in_len)
+{
+ WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
+
+ if (data->tls_out_len == 0) {
+ /* No more data to send out - expect to receive more data from
+ * the peer. */
+ int res = eap_tls_data_reassemble(sm, data, &in_data, &in_len);
+ if (res < 0 || res == 1) {
+ wpa_printf(MSG_DEBUG, "SSL: data reassembly failed");
+ return res;
+ }
+ /* Full TLS message reassembled - continue handshake processing
+ */
+ if (data->tls_out) {
+ /* This should not happen.. */
+ wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
+ "pending tls_out data even though "
+ "tls_out_len = 0");
+ free(data->tls_out);
+ WPA_ASSERT(data->tls_out == NULL);
+ }
+ data->tls_out = tls_connection_server_handshake(
+ sm->ssl_ctx, data->conn, in_data, in_len,
+ &data->tls_out_len);
+
+ /* Clear reassembled input data (if the buffer was needed). */
+ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
+ free(data->tls_in);
+ data->tls_in = NULL;
+ }
+
+ if (data->tls_out == NULL) {
+ wpa_printf(MSG_DEBUG, "SSL: failed to generate output data");
+ data->tls_out_len = 0;
+ return -1;
+ }
+ if (data->tls_out_len == 0) {
+ /* TLS negotiation should now be complete since all other cases
+ * needing more that should have been catched above based on
+ * the TLS Message Length field. */
+ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
+ free(data->tls_out);
+ data->tls_out = NULL;
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
+ "%lu bytes)",
+ (unsigned long) data->tls_out_len - data->tls_out_pos,
+ (unsigned long) data->tls_out_len);
+
+ return 0;
+}
+
+
+int eap_tls_buildReq_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ int eap_type, int peap_version, u8 id,
+ u8 **out_data, size_t *out_len)
+{
+ size_t len;
+ u8 *pos, *flags;
+ struct eap_hdr *req;
+
+ *out_len = 0;
+
+ req = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit);
+ if (req == NULL) {
+ *out_data = NULL;
+ return -1;
+ }
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ pos = (u8 *) (req + 1);
+ *pos++ = eap_type;
+ flags = pos++;
+ *flags = peap_version;
+ if (data->tls_out_pos == 0 &&
+ data->tls_out_len > data->tls_out_limit) {
+ *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+ *pos++ = (data->tls_out_len >> 24) & 0xff;
+ *pos++ = (data->tls_out_len >> 16) & 0xff;
+ *pos++ = (data->tls_out_len >> 8) & 0xff;
+ *pos++ = data->tls_out_len & 0xff;
+ }
+
+ len = data->tls_out_len - data->tls_out_pos;
+ if (len > data->tls_out_limit) {
+ *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ len = data->tls_out_limit;
+ wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
+ "will follow", (unsigned long) len);
+ }
+ memcpy(pos, &data->tls_out[data->tls_out_pos], len);
+ data->tls_out_pos += len;
+ *out_len = (pos - (u8 *) req) + len;
+ req->length = htons(*out_len);
+ *out_data = (u8 *) req;
+
+ if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
+ data->tls_out_len = 0;
+ data->tls_out_pos = 0;
+ free(data->tls_out);
+ data->tls_out = NULL;
+ }
+
+ return 0;
+}
+
+
+u8 * eap_tls_build_ack(size_t *reqDataLen, u8 id, int eap_type,
+ int peap_version)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+
+ *reqDataLen = sizeof(struct eap_hdr) + 2;
+ req = malloc(*reqDataLen);
+ if (req == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = eap_type; /* Type */
+ *pos = peap_version; /* Flags */
+ return (u8 *) req;
+}
diff --git a/contrib/hostapd/eap_tls_common.h b/contrib/hostapd/eap_tls_common.h
new file mode 100644
index 000000000000..659ee849f7b0
--- /dev/null
+++ b/contrib/hostapd/eap_tls_common.h
@@ -0,0 +1,47 @@
+#ifndef EAP_TLS_COMMON_H
+#define EAP_TLS_COMMON_H
+
+struct eap_ssl_data {
+ struct tls_connection *conn;
+
+ u8 *tls_out;
+ size_t tls_out_len;
+ size_t tls_out_pos;
+ size_t tls_out_limit;
+ u8 *tls_in;
+ size_t tls_in_len;
+ size_t tls_in_left;
+ size_t tls_in_total;
+
+ int phase2;
+
+ struct eap_sm *eap;
+};
+
+
+/* EAP TLS Flags */
+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TLS_FLAGS_START 0x20
+#define EAP_PEAP_VERSION_MASK 0x07
+
+ /* could be up to 128 bytes, but only the first 64 bytes are used */
+#define EAP_TLS_KEY_LEN 64
+
+
+int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+ int verify_peer);
+void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
+u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len);
+int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 **in_data, size_t *in_len);
+int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ u8 *in_data, size_t in_len);
+int eap_tls_buildReq_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+ int eap_type, int peap_version, u8 id,
+ u8 **out_data, size_t *out_len);
+u8 * eap_tls_build_ack(size_t *reqDataLen, u8 id, int eap_type,
+ int peap_version);
+
+#endif /* EAP_TLS_COMMON_H */
diff --git a/contrib/hostapd/eap_tlv.c b/contrib/hostapd/eap_tlv.c
new file mode 100644
index 000000000000..b7609dcf2e91
--- /dev/null
+++ b/contrib/hostapd/eap_tlv.c
@@ -0,0 +1,248 @@
+/*
+ * hostapd / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+#define EAP_TLV_CRYPTO_BINDING_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+
+struct eap_tlv_data {
+ enum { CONTINUE, SUCCESS, FAILURE } state;
+};
+
+
+static void * eap_tlv_init(struct eap_sm *sm)
+{
+ struct eap_tlv_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->state = CONTINUE;
+
+ return data;
+}
+
+
+static void eap_tlv_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_tlv_data *data = priv;
+ free(data);
+}
+
+
+static u8 * eap_tlv_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+ u16 status;
+
+ if (sm->tlv_request == TLV_REQ_SUCCESS) {
+ status = EAP_TLV_RESULT_SUCCESS;
+ } else {
+ status = EAP_TLV_RESULT_FAILURE;
+ }
+
+ *reqDataLen = sizeof(struct eap_hdr) + 1 + 6;
+ req = malloc(*reqDataLen);
+ if (req == NULL)
+ return NULL;
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = host_to_be16(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_TLV;
+ *pos++ = 0x80; /* Mandatory */
+ *pos++ = EAP_TLV_RESULT_TLV;
+ /* Length */
+ *pos++ = 0;
+ *pos++ = 2;
+ /* Status */
+ *pos++ = status >> 8;
+ *pos++ = status & 0xff;
+
+ return (u8 *) req;
+}
+
+
+static Boolean eap_tlv_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_TLV ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-TLV: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_tlv_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_tlv_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos;
+ int len;
+ size_t left;
+ u8 *result_tlv = NULL;
+ size_t result_tlv_len = 0;
+ int tlv_type, mandatory, tlv_len;
+
+ resp = (struct eap_hdr *) respData;
+ len = ntohs(resp->length);
+ pos = (u8 *) (resp + 1);
+
+ /* Parse TLVs */
+ left = be_to_host16(resp->length) - sizeof(struct eap_hdr) - 1;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+ while (left >= 4) {
+ mandatory = !!(pos[0] & 0x80);
+ tlv_type = pos[0] & 0x3f;
+ tlv_type = (tlv_type << 8) | pos[1];
+ tlv_len = ((int) pos[2] << 8) | pos[3];
+ pos += 4;
+ left -= 4;
+ if (tlv_len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+ "(tlv_len=%d left=%lu)", tlv_len,
+ (unsigned long) left);
+ data->state = FAILURE;
+ return;
+ }
+ switch (tlv_type) {
+ case EAP_TLV_RESULT_TLV:
+ result_tlv = pos;
+ result_tlv_len = tlv_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+ "%d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ data->state = FAILURE;
+ return;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ }
+
+ pos += tlv_len;
+ left -= tlv_len;
+ }
+ if (left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+ "Request (left=%lu)", (unsigned long) left);
+ data->state = FAILURE;
+ return;
+ }
+
+ /* Process supported TLVs */
+ if (result_tlv) {
+ int status;
+ const char *requested;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+ result_tlv, result_tlv_len);
+ if (result_tlv_len < 2) {
+ wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+ "(len=%lu)",
+ (unsigned long) result_tlv_len);
+ data->state = FAILURE;
+ return;
+ }
+ requested = sm->tlv_request == TLV_REQ_SUCCESS ? "Success" :
+ "Failure";
+ status = ((int) result_tlv[0] << 8) | result_tlv[1];
+ if (status == EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+ "- requested %s", requested);
+ if (sm->tlv_request == TLV_REQ_SUCCESS)
+ data->state = SUCCESS;
+ else
+ data->state = FAILURE;
+
+ } else if (status == EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure - "
+ "requested %s", requested);
+ if (sm->tlv_request == TLV_REQ_FAILURE)
+ data->state = SUCCESS;
+ else
+ data->state = FAILURE;
+ } else {
+ wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+ "Status %d", status);
+ data->state = FAILURE;
+ }
+ }
+}
+
+
+static Boolean eap_tlv_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_tlv_data *data = priv;
+ return data->state != CONTINUE;
+}
+
+
+static Boolean eap_tlv_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_tlv_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_tlv =
+{
+ .method = EAP_TYPE_TLV,
+ .name = "TLV",
+ .init = eap_tlv_init,
+ .reset = eap_tlv_reset,
+ .buildReq = eap_tlv_buildReq,
+ .check = eap_tlv_check,
+ .process = eap_tlv_process,
+ .isDone = eap_tlv_isDone,
+ .isSuccess = eap_tlv_isSuccess,
+};
diff --git a/contrib/hostapd/eap_ttls.c b/contrib/hostapd/eap_ttls.c
new file mode 100644
index 000000000000..1e4be75c70b7
--- /dev/null
+++ b/contrib/hostapd/eap_ttls.c
@@ -0,0 +1,1183 @@
+/*
+ * hostapd / EAP-TTLS (draft-ietf-pppext-eap-ttls-05.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "ms_funcs.h"
+#include "md5.h"
+#include "tls.h"
+#include "eap_ttls.h"
+
+#define EAP_TTLS_VERSION 0
+
+
+static void eap_ttls_reset(struct eap_sm *sm, void *priv);
+
+
+struct eap_ttls_data {
+ struct eap_ssl_data ssl;
+ enum {
+ START, PHASE1, PHASE2_START, PHASE2_METHOD,
+ PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
+ } state;
+
+ int ttls_version;
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int mschapv2_resp_ok;
+ u8 mschapv2_auth_response[20];
+ u8 mschapv2_ident;
+};
+
+
+static const char * eap_ttls_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case PHASE1:
+ return "PHASE1";
+ case PHASE2_START:
+ return "PHASE2_START";
+ case PHASE2_METHOD:
+ return "PHASE2_METHOD";
+ case PHASE2_MSCHAPV2_RESP:
+ return "PHASE2_MSCHAPV2_RESP";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_ttls_state(struct eap_ttls_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s",
+ eap_ttls_state_txt(data->state),
+ eap_ttls_state_txt(state));
+ data->state = state;
+}
+
+
+static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
+ int mandatory, size_t len)
+{
+ struct ttls_avp_vendor *avp;
+ u8 flags;
+ size_t hdrlen;
+
+ avp = (struct ttls_avp_vendor *) avphdr;
+ flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
+ if (vendor_id) {
+ flags |= AVP_FLAGS_VENDOR;
+ hdrlen = sizeof(*avp);
+ avp->vendor_id = host_to_be32(vendor_id);
+ } else {
+ hdrlen = sizeof(struct ttls_avp);
+ }
+
+ avp->avp_code = host_to_be32(avp_code);
+ avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+
+ return avphdr + hdrlen;
+}
+
+
+static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code,
+ int mandatory)
+{
+ u8 *avp, *pos;
+
+ avp = malloc(sizeof(struct ttls_avp) + *resp_len + 4);
+ if (avp == NULL) {
+ free(*resp);
+ *resp_len = 0;
+ return -1;
+ }
+
+ pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, *resp_len);
+ memcpy(pos, *resp, *resp_len);
+ pos += *resp_len;
+ AVP_PAD(avp, pos);
+ free(*resp);
+ *resp = avp;
+ *resp_len = pos - avp;
+ return 0;
+}
+
+
+struct eap_ttls_avp {
+ /* Note: eap is allocated memory; caller is responsible for freeing
+ * it. All the other pointers are pointing to the packet data, i.e.,
+ * they must not be freed separately. */
+ u8 *eap;
+ size_t eap_len;
+ u8 *user_name;
+ size_t user_name_len;
+ u8 *user_password;
+ size_t user_password_len;
+ u8 *chap_challenge;
+ size_t chap_challenge_len;
+ u8 *chap_password;
+ size_t chap_password_len;
+ u8 *mschap_challenge;
+ size_t mschap_challenge_len;
+ u8 *mschap_response;
+ size_t mschap_response_len;
+ u8 *mschap2_response;
+ size_t mschap2_response_len;
+};
+
+
+static int eap_ttls_avp_parse(u8 *buf, size_t len, struct eap_ttls_avp *parse)
+{
+ struct ttls_avp *avp;
+ u8 *pos;
+ int left;
+
+ pos = buf;
+ left = len;
+ memset(parse, 0, sizeof(*parse));
+
+ while (left > 0) {
+ u32 avp_code, avp_length, vendor_id = 0;
+ u8 avp_flags, *dpos;
+ size_t pad, dlen;
+ avp = (struct ttls_avp *) pos;
+ avp_code = be_to_host32(avp->avp_code);
+ avp_length = be_to_host32(avp->avp_length);
+ avp_flags = (avp_length >> 24) & 0xff;
+ avp_length &= 0xffffff;
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
+ "length=%d", (int) avp_code, avp_flags,
+ (int) avp_length);
+ if (avp_length > left) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
+ "(len=%d, left=%d) - dropped",
+ (int) avp_length, left);
+ return -1;
+ }
+ dpos = (u8 *) (avp + 1);
+ dlen = avp_length - sizeof(*avp);
+ if (avp_flags & AVP_FLAGS_VENDOR) {
+ if (dlen < 4) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP "
+ "underflow");
+ return -1;
+ }
+ vendor_id = be_to_host32(* (u32 *) dpos);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
+ (int) vendor_id);
+ dpos += 4;
+ dlen -= 4;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
+
+ if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
+ if (parse->eap == NULL) {
+ parse->eap = malloc(dlen);
+ if (parse->eap == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: "
+ "failed to allocate memory "
+ "for Phase 2 EAP data");
+ return -1;
+ }
+ memcpy(parse->eap, dpos, dlen);
+ parse->eap_len = dlen;
+ } else {
+ u8 *neweap = realloc(parse->eap,
+ parse->eap_len + dlen);
+ if (neweap == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: "
+ "failed to allocate memory "
+ "for Phase 2 EAP data");
+ free(parse->eap);
+ parse->eap = NULL;
+ return -1;
+ }
+ memcpy(neweap + parse->eap_len, dpos, dlen);
+ parse->eap = neweap;
+ parse->eap_len += dlen;
+ }
+ } else if (vendor_id == 0 &&
+ avp_code == RADIUS_ATTR_USER_NAME) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name",
+ dpos, dlen);
+ parse->user_name = dpos;
+ parse->user_name_len = dlen;
+ } else if (vendor_id == 0 &&
+ avp_code == RADIUS_ATTR_USER_PASSWORD) {
+ u8 *password = dpos;
+ size_t password_len = dlen;
+ while (password_len > 0 &&
+ password[password_len - 1] == '\0') {
+ password_len--;
+ }
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: "
+ "User-Password (PAP)",
+ password, password_len);
+ parse->user_password = password;
+ parse->user_password_len = password_len;
+ } else if (vendor_id == 0 &&
+ avp_code == RADIUS_ATTR_CHAP_CHALLENGE) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TTLS: CHAP-Challenge (CHAP)",
+ dpos, dlen);
+ parse->chap_challenge = dpos;
+ parse->chap_challenge_len = dlen;
+ } else if (vendor_id == 0 &&
+ avp_code == RADIUS_ATTR_CHAP_PASSWORD) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TTLS: CHAP-Password (CHAP)",
+ dpos, dlen);
+ parse->chap_password = dpos;
+ parse->chap_password_len = dlen;
+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+ avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TTLS: MS-CHAP-Challenge",
+ dpos, dlen);
+ parse->mschap_challenge = dpos;
+ parse->mschap_challenge_len = dlen;
+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+ avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TTLS: MS-CHAP-Response (MSCHAP)",
+ dpos, dlen);
+ parse->mschap_response = dpos;
+ parse->mschap_response_len = dlen;
+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+ avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)",
+ dpos, dlen);
+ parse->mschap2_response = dpos;
+ parse->mschap2_response_len = dlen;
+ } else if (avp_flags & AVP_FLAGS_MANDATORY) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported "
+ "mandatory AVP code %d vendor_id %d - "
+ "dropped", (int) avp_code, (int) vendor_id);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported "
+ "AVP code %d vendor_id %d",
+ (int) avp_code, (int) vendor_id);
+ }
+
+ pad = (4 - (avp_length & 3)) & 3;
+ pos += avp_length + pad;
+ left -= avp_length + pad;
+ }
+
+ return 0;
+}
+
+
+static void * eap_ttls_init(struct eap_sm *sm)
+{
+ struct eap_ttls_data *data;
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return data;
+ memset(data, 0, sizeof(*data));
+ data->ttls_version = EAP_TTLS_VERSION;
+ data->state = START;
+
+ if (eap_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+ eap_ttls_reset(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_ttls_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_ttls_data *data = priv;
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->reset(sm, data->phase2_priv);
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ free(data);
+}
+
+
+static u8 * eap_ttls_build_start(struct eap_sm *sm, struct eap_ttls_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+
+ *reqDataLen = sizeof(*req) + 2;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for"
+ " request");
+ eap_ttls_state(data, FAILURE);
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_TTLS;
+ *pos = EAP_TLS_FLAGS_START | data->ttls_version;
+
+ eap_ttls_state(data, PHASE1);
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_ttls_build_req(struct eap_sm *sm, struct eap_ttls_data *data,
+ int id, size_t *reqDataLen)
+{
+ int res;
+ u8 *req;
+
+ res = eap_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id, &req,
+ reqDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, starting "
+ "Phase2");
+ eap_ttls_state(data, PHASE2_START);
+ }
+
+ if (res == 1)
+ return eap_tls_build_ack(reqDataLen, id, EAP_TYPE_TTLS,
+ data->ttls_version);
+ return req;
+}
+
+
+static u8 * eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
+ int id, u8 *plain, size_t plain_len,
+ size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *req;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented. */
+ req = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (req == NULL)
+ return NULL;
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_TTLS;
+ *pos++ = data->ttls_version;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
+ "data");
+ free(req);
+ return NULL;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ req->length = host_to_be16(*out_len);
+ return (u8 *) req;
+}
+
+
+static u8 * eap_ttls_build_phase2_eap_req(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *req, *encr_req;
+ size_t req_len;
+
+
+ req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
+ &req_len);
+ if (req == NULL)
+ return NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encapsulate Phase 2 data",
+ req, req_len);
+
+ if (eap_ttls_avp_encapsulate(&req, &req_len, RADIUS_ATTR_EAP_MESSAGE,
+ 1) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate "
+ "packet");
+ return NULL;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase "
+ "2 data", req, req_len);
+
+ encr_req = eap_ttls_encrypt(sm, data, id, req, req_len, reqDataLen);
+ free(req);
+
+ return encr_req;
+}
+
+
+static u8 * eap_ttls_build_phase2_mschapv2(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *req, *encr_req, *pos, *end;
+ size_t req_len;
+ int i;
+
+ pos = req = malloc(100);
+ if (req == NULL)
+ return NULL;
+ end = req + 200;
+
+ if (data->mschapv2_resp_ok) {
+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS,
+ RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
+ *pos++ = data->mschapv2_ident;
+ pos += snprintf((char *) pos, end - pos, "S=");
+ for (i = 0; i < sizeof(data->mschapv2_auth_response); i++) {
+ pos += snprintf((char *) pos, end - pos, "%02X",
+ data->mschapv2_auth_response[i]);
+ }
+ } else {
+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR,
+ RADIUS_VENDOR_ID_MICROSOFT, 1, 6);
+ memcpy(pos, "Failed", 6);
+ pos += 6;
+ AVP_PAD(req, pos);
+ }
+
+ req_len = pos - req;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
+ "data", req, req_len);
+
+ encr_req = eap_ttls_encrypt(sm, data, id, req, req_len, reqDataLen);
+ free(req);
+
+ return encr_req;
+}
+
+
+static u8 * eap_ttls_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_ttls_data *data = priv;
+
+ switch (data->state) {
+ case START:
+ return eap_ttls_build_start(sm, data, id, reqDataLen);
+ case PHASE1:
+ return eap_ttls_build_req(sm, data, id, reqDataLen);
+ case PHASE2_METHOD:
+ return eap_ttls_build_phase2_eap_req(sm, data, id, reqDataLen);
+ case PHASE2_MSCHAPV2_RESP:
+ return eap_ttls_build_phase2_mschapv2(sm, data, id,
+ reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
+ __func__, data->state);
+ return NULL;
+ }
+}
+
+
+static Boolean eap_ttls_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+ size_t len;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_TTLS ||
+ (len = ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ const u8 *user_password,
+ size_t user_password_len)
+{
+ /* TODO: add support for verifying that the user entry accepts
+ * EAP-TTLS/PAP. */
+ if (!sm->user || !sm->user->password) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No user password "
+ "configured");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (sm->user->password_len != user_password_len ||
+ memcmp(sm->user->password, user_password, user_password_len) != 0)
+ {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
+ eap_ttls_state(data, SUCCESS);
+}
+
+
+static void eap_ttls_process_phase2_chap(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ const u8 *challenge,
+ size_t challenge_len,
+ const u8 *password,
+ size_t password_len)
+{
+ MD5_CTX context;
+ u8 *chal, hash[MD5_MAC_LEN];
+
+ if (challenge == NULL || password == NULL ||
+ challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN ||
+ password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes "
+ "(challenge len %lu password len %lu)",
+ (unsigned long) challenge_len,
+ (unsigned long) password_len);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ /* TODO: add support for verifying that the user entry accepts
+ * EAP-TTLS/CHAP. */
+ if (!sm->user || !sm->user->password) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No user password "
+ "configured");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
+ if (chal == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate "
+ "challenge from TLS data");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 ||
+ password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch");
+ free(chal);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+ free(chal);
+
+ /* MD5(Ident + Password + Challenge) */
+ MD5Init(&context);
+ MD5Update(&context, password, 1);
+ MD5Update(&context, sm->user->password, sm->user->password_len);
+ MD5Update(&context, challenge, challenge_len);
+ MD5Final(hash, &context);
+
+ if (memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
+ eap_ttls_state(data, SUCCESS);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
+ eap_ttls_state(data, FAILURE);
+ }
+}
+
+
+static void eap_ttls_process_phase2_mschap(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ u8 *challenge, size_t challenge_len,
+ u8 *response, size_t response_len)
+{
+ u8 *chal, nt_response[24];
+
+ if (challenge == NULL || response == NULL ||
+ challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN ||
+ response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP "
+ "attributes (challenge len %lu response len %lu)",
+ (unsigned long) challenge_len,
+ (unsigned long) response_len);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ /* TODO: add support for verifying that the user entry accepts
+ * EAP-TTLS/MSCHAP. */
+ if (!sm->user || !sm->user->password) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password "
+ "configured");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
+ if (chal == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate "
+ "challenge from TLS data");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 ||
+ response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch");
+ free(chal);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+ free(chal);
+
+ nt_challenge_response(challenge, sm->user->password,
+ sm->user->password_len, nt_response);
+
+ if (memcmp(nt_response, response + 2 + 24, 24) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
+ eap_ttls_state(data, SUCCESS);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
+ response + 2 + 24, 24);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected",
+ nt_response, 24);
+ eap_ttls_state(data, FAILURE);
+ }
+}
+
+
+static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ u8 *challenge,
+ size_t challenge_len,
+ u8 *response, size_t response_len)
+{
+ u8 *chal, *username, nt_response[24], *pos, *rx_resp, *peer_challenge,
+ *auth_challenge;
+ size_t username_len;
+ int i;
+
+ if (challenge == NULL || response == NULL ||
+ challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN ||
+ response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 "
+ "attributes (challenge len %lu response len %lu)",
+ (unsigned long) challenge_len,
+ (unsigned long) response_len);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ /* TODO: add support for verifying that the user entry accepts
+ * EAP-TTLS/MSCHAPV2. */
+ if (!sm->user || !sm->user->password) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password "
+ "configured");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ /* MSCHAPv2 does not include optional domain name in the
+ * challenge-response calculation, so remove domain prefix
+ * (if present). */
+ username = sm->identity;
+ username_len = sm->identity_len;
+ pos = username;
+ for (i = 0; i < username_len; i++) {
+ if (username[i] == '\\') {
+ username_len -= i + 1;
+ username += i + 1;
+ break;
+ }
+ }
+
+ chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
+ if (chal == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate "
+ "challenge from TLS data");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 ||
+ response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch");
+ free(chal);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+ free(chal);
+
+ auth_challenge = challenge;
+ peer_challenge = response + 2;
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User",
+ username, username_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge",
+ auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge",
+ peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+
+ generate_nt_response(auth_challenge, peer_challenge,
+ username, username_len,
+ sm->user->password, sm->user->password_len,
+ nt_response);
+
+ rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
+ if (memcmp(nt_response, rx_resp, 24) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
+ "NT-Response");
+ data->mschapv2_resp_ok = 1;
+
+ generate_authenticator_response(sm->user->password,
+ sm->user->password_len,
+ peer_challenge,
+ auth_challenge,
+ username, username_len,
+ nt_response,
+ data->mschapv2_auth_response);
+
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid "
+ "NT-Response");
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received",
+ rx_resp, 24);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected",
+ nt_response, 24);
+ data->mschapv2_resp_ok = 0;
+ }
+ eap_ttls_state(data, PHASE2_MSCHAPV2_RESP);
+ data->mschapv2_ident = response[0];
+}
+
+
+static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
+ struct eap_ttls_data *data, u8 eap_type)
+{
+ if (data->phase2_priv && data->phase2_method) {
+ data->phase2_method->reset(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ }
+ data->phase2_method = eap_sm_get_eap_methods(eap_type);
+ if (!data->phase2_method)
+ return -1;
+
+ sm->init_phase2 = 1;
+ data->phase2_priv = data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+ return 0;
+}
+
+
+static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ u8 *in_data, size_t in_len)
+{
+ u8 next_type = EAP_TYPE_NONE;
+ struct eap_hdr *hdr;
+ u8 *pos;
+ size_t left;
+
+ if (data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not "
+ "initialized?!", __func__);
+ return;
+ }
+
+ hdr = (struct eap_hdr *) in_data;
+ pos = (u8 *) (hdr + 1);
+ left = in_len - sizeof(*hdr);
+
+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; "
+ "allowed types", pos + 1, left - 1);
+ eap_sm_process_nak(sm, pos + 1, left - 1);
+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index] !=
+ EAP_TYPE_NONE) {
+ next_type =
+ sm->user->methods[sm->user_eap_method_index++];
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
+ next_type);
+ eap_ttls_phase2_eap_init(sm, data, next_type);
+ } else {
+ eap_ttls_state(data, FAILURE);
+ }
+ return;
+ }
+
+ if (data->phase2_method->check(sm, data->phase2_priv, in_data,
+ in_len)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to "
+ "ignore the packet");
+ return;
+ }
+
+ data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
+
+ if (!data->phase2_method->isDone(sm, data->phase2_priv))
+ return;
+
+ if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ switch (data->state) {
+ case PHASE2_START:
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 "
+ "Identity not found in the user "
+ "database",
+ sm->identity, sm->identity_len);
+ eap_ttls_state(data, FAILURE);
+ break;
+ }
+
+ eap_ttls_state(data, PHASE2_METHOD);
+ next_type = sm->user->methods[0];
+ sm->user_eap_method_index = 1;
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
+ break;
+ case PHASE2_METHOD:
+ eap_ttls_state(data, SUCCESS);
+ break;
+ case FAILURE:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
+ __func__, data->state);
+ break;
+ }
+
+ eap_ttls_phase2_eap_init(sm, data, next_type);
+}
+
+
+static void eap_ttls_process_phase2_eap(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ const u8 *eap, size_t eap_len)
+{
+ struct eap_hdr *hdr;
+ size_t len;
+
+ if (data->state == PHASE2_START) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2");
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to "
+ "initialize EAP-Identity");
+ return;
+ }
+ }
+
+ if (eap_len < sizeof(*hdr)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP "
+ "packet (len=%lu)", (unsigned long) eap_len);
+ return;
+ }
+
+ hdr = (struct eap_hdr *) eap;
+ len = be_to_host16(hdr->length);
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d "
+ "identifier=%d length=%lu", hdr->code, hdr->identifier,
+ (unsigned long) len);
+ if (len > eap_len) {
+ wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2"
+ " EAP frame (hdr len=%lu, data len in AVP=%lu)",
+ (unsigned long) len, (unsigned long) eap_len);
+ return;
+ }
+
+ switch (hdr->code) {
+ case EAP_CODE_RESPONSE:
+ eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr,
+ len);
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in "
+ "Phase 2 EAP header", hdr->code);
+ break;
+ }
+}
+
+
+static void eap_ttls_process_phase2(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ struct eap_hdr *resp,
+ u8 *in_data, size_t in_len)
+{
+ u8 *in_decrypted;
+ int buf_len, len_decrypted, res;
+ struct eap_ttls_avp parse;
+
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
+ " Phase 2", (unsigned long) in_len);
+
+ res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
+ if (res < 0 || res == 1)
+ return;
+
+ buf_len = in_len;
+ if (data->ssl.tls_in_total > buf_len)
+ buf_len = data->ssl.tls_in_total;
+ in_decrypted = malloc(buf_len);
+ if (in_decrypted == NULL) {
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory "
+ "for decryption");
+ return;
+ }
+
+ len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_data, in_len,
+ in_decrypted, buf_len);
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ if (len_decrypted < 0) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
+ "data");
+ free(in_decrypted);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
+ in_decrypted, len_decrypted);
+
+ if (eap_ttls_avp_parse(in_decrypted, len_decrypted, &parse) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs");
+ free(in_decrypted);
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ if (parse.user_name) {
+ free(sm->identity);
+ sm->identity = malloc(parse.user_name_len);
+ if (sm->identity) {
+ memcpy(sm->identity, parse.user_name,
+ parse.user_name_len);
+ sm->identity_len = parse.user_name_len;
+ }
+ if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
+ != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not "
+ "found in the user database");
+ eap_ttls_state(data, FAILURE);
+ goto done;
+ }
+ }
+
+ if (parse.eap) {
+ eap_ttls_process_phase2_eap(sm, data, parse.eap,
+ parse.eap_len);
+ } else if (parse.user_password) {
+ eap_ttls_process_phase2_pap(sm, data, parse.user_password,
+ parse.user_password_len);
+ } else if (parse.chap_password) {
+ eap_ttls_process_phase2_chap(sm, data,
+ parse.chap_challenge,
+ parse.chap_challenge_len,
+ parse.chap_password,
+ parse.chap_password_len);
+ } else if (parse.mschap_response) {
+ eap_ttls_process_phase2_mschap(sm, data,
+ parse.mschap_challenge,
+ parse.mschap_challenge_len,
+ parse.mschap_response,
+ parse.mschap_response_len);
+ } else if (parse.mschap2_response) {
+ eap_ttls_process_phase2_mschapv2(sm, data,
+ parse.mschap_challenge,
+ parse.mschap_challenge_len,
+ parse.mschap2_response,
+ parse.mschap2_response_len);
+ }
+
+done:
+ free(in_decrypted);
+ free(parse.eap);
+ }
+
+
+static void eap_ttls_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_ttls_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, flags;
+ int left;
+ unsigned int tls_msg_len;
+ int peer_version;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ flags = *pos++;
+ left = htons(resp->length) - sizeof(struct eap_hdr) - 2;
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) respDataLen, flags);
+ peer_version = flags & EAP_PEAP_VERSION_MASK;
+ if (peer_version < data->ttls_version) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
+ "use version %d",
+ peer_version, data->ttls_version, peer_version);
+ data->ttls_version = peer_version;
+
+ }
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
+ "length");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ switch (data->state) {
+ case PHASE1:
+ if (eap_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: TLS processing "
+ "failed");
+ eap_ttls_state(data, FAILURE);
+ }
+ break;
+ case PHASE2_START:
+ case PHASE2_METHOD:
+ eap_ttls_process_phase2(sm, data, resp, pos, left);
+ break;
+ case PHASE2_MSCHAPV2_RESP:
+ if (data->mschapv2_resp_ok && left == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
+ "acknowledged response");
+ eap_ttls_state(data, SUCCESS);
+ } else if (!data->mschapv2_resp_ok) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
+ "acknowledged error");
+ eap_ttls_state(data, FAILURE);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected "
+ "frame from peer (payload len %d, expected "
+ "empty frame)", left);
+ eap_ttls_state(data, FAILURE);
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s",
+ data->state, __func__);
+ break;
+ }
+}
+
+
+static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_ttls_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = eap_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_LEN);
+ if (eapKeyData) {
+ *len = EAP_TLS_KEY_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived key",
+ eapKeyData, EAP_TLS_KEY_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
+ }
+
+ return eapKeyData;
+}
+
+
+static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_ttls_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+const struct eap_method eap_method_ttls =
+{
+ .method = EAP_TYPE_TTLS,
+ .name = "TTLS",
+ .init = eap_ttls_init,
+ .reset = eap_ttls_reset,
+ .buildReq = eap_ttls_buildReq,
+ .check = eap_ttls_check,
+ .process = eap_ttls_process,
+ .isDone = eap_ttls_isDone,
+ .getKey = eap_ttls_getKey,
+ .isSuccess = eap_ttls_isSuccess,
+};
diff --git a/contrib/hostapd/eap_ttls.h b/contrib/hostapd/eap_ttls.h
new file mode 100644
index 000000000000..a187db4d34f7
--- /dev/null
+++ b/contrib/hostapd/eap_ttls.h
@@ -0,0 +1,57 @@
+#ifndef EAP_TTLS_H
+#define EAP_TTLS_H
+
+struct ttls_avp {
+ u32 avp_code;
+ u32 avp_length; /* 8-bit flags, 24-bit length;
+ * length includes AVP header */
+ /* optional 32-bit Vendor-ID */
+ /* Data */
+};
+
+struct ttls_avp_vendor {
+ u32 avp_code;
+ u32 avp_length; /* 8-bit flags, 24-bit length;
+ * length includes AVP header */
+ u32 vendor_id;
+ /* Data */
+};
+
+#define AVP_FLAGS_VENDOR 0x80
+#define AVP_FLAGS_MANDATORY 0x40
+
+#define AVP_PAD(start, pos) \
+do { \
+ int pad; \
+ pad = (4 - (((pos) - (start)) & 3)) & 3; \
+ memset((pos), 0, pad); \
+ pos += pad; \
+} while(0)
+
+
+/* RFC 2865 */
+#define RADIUS_ATTR_USER_NAME 1
+#define RADIUS_ATTR_USER_PASSWORD 2
+#define RADIUS_ATTR_CHAP_PASSWORD 3
+#define RADIUS_ATTR_REPLY_MESSAGE 18
+#define RADIUS_ATTR_CHAP_CHALLENGE 60
+#define RADIUS_ATTR_EAP_MESSAGE 79
+
+/* RFC 2548 */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
+#define RADIUS_ATTR_MS_CHAP_ERROR 2
+#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
+#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
+#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
+#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
+#define RADIUS_ATTR_MS_CHAP2_CPW 27
+
+#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
+#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
+#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
+#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
+#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
+#define EAP_TTLS_CHAP_PASSWORD_LEN 16
+
+#endif /* EAP_TTLS_H */
diff --git a/contrib/hostapd/eapol_sm.c b/contrib/hostapd/eapol_sm.c
new file mode 100644
index 000000000000..fce7c6d3391a
--- /dev/null
+++ b/contrib/hostapd/eapol_sm.c
@@ -0,0 +1,1183 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / IEEE 802.1X Authenticator - EAPOL state machine
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "eapol_sm.h"
+#include "eloop.h"
+#include "wpa.h"
+#include "sta_info.h"
+#include "eap.h"
+
+static struct eapol_callbacks eapol_cb;
+
+/* EAPOL state machines are described in IEEE Std 802.1X-REV-d11, Chap. 8.2 */
+
+#define setPortAuthorized() \
+ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 1)
+#define setPortUnauthorized() \
+ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 0)
+
+/* procedures */
+#define txCannedFail() ieee802_1x_tx_canned_eap(sm->hapd, sm->sta, 0)
+#define txCannedSuccess() ieee802_1x_tx_canned_eap(sm->hapd, sm->sta, 1)
+#define txReq() ieee802_1x_tx_req(sm->hapd, sm->sta)
+#define sendRespToServer() ieee802_1x_send_resp_to_server(sm->hapd, sm->sta)
+#define abortAuth() ieee802_1x_abort_auth(sm->hapd, sm->sta)
+#define txKey() ieee802_1x_tx_key(sm->hapd, sm->sta)
+#define processKey() do { } while (0)
+
+
+/* Definitions for clarifying state machine implementation */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_state_machine \
+*sm)
+
+#define SM_ENTRY(machine, _state, _data) \
+sm->_data.state = machine ## _ ## _state; \
+if (sm->hapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \
+ printf("IEEE 802.1X: " MACSTR " " #machine " entering state " #_state \
+ "\n", MAC2STR(sm->addr));
+
+#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)
+
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
+
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+
+
+/* Port Timers state machine - implemented as a function that will be called
+ * once a second as a registered event loop timeout */
+
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+ struct eapol_state_machine *state = timeout_ctx;
+
+ if (state->aWhile > 0)
+ state->aWhile--;
+ if (state->quietWhile > 0)
+ state->quietWhile--;
+ if (state->reAuthWhen > 0)
+ state->reAuthWhen--;
+
+ if (state->hapd->conf->debug >= HOSTAPD_DEBUG_MSGDUMPS)
+ printf("IEEE 802.1X: " MACSTR " Port Timers TICK "
+ "(timers: %d %d %d)\n", MAC2STR(state->addr),
+ state->aWhile, state->quietWhile, state->reAuthWhen);
+
+ eapol_sm_step(state);
+
+ eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
+}
+
+
+
+/* Authenticator PAE state machine */
+
+SM_STATE(AUTH_PAE, INITIALIZE)
+{
+ SM_ENTRY(AUTH_PAE, INITIALIZE, auth_pae);
+ sm->auth_pae.portMode = Auto;
+
+ sm->currentId = 255;
+}
+
+
+SM_STATE(AUTH_PAE, DISCONNECTED)
+{
+ int from_initialize = sm->auth_pae.state == AUTH_PAE_INITIALIZE;
+
+ if (sm->auth_pae.eapolLogoff) {
+ if (sm->auth_pae.state == AUTH_PAE_CONNECTING)
+ sm->auth_pae.authEapLogoffsWhileConnecting++;
+ else if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED)
+ sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
+ }
+
+ SM_ENTRY(AUTH_PAE, DISCONNECTED, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->auth_pae.reAuthCount = 0;
+ sm->auth_pae.eapolLogoff = FALSE;
+ if (!from_initialize) {
+ if (sm->flags & EAPOL_SM_PREAUTH)
+ rsn_preauth_finished(sm->hapd, sm->sta, 0);
+ }
+}
+
+
+SM_STATE(AUTH_PAE, RESTART)
+{
+ if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED) {
+ if (sm->reAuthenticate)
+ sm->auth_pae.authAuthReauthsWhileAuthenticated++;
+ if (sm->auth_pae.eapolStart)
+ sm->auth_pae.authAuthEapStartsWhileAuthenticated++;
+ if (sm->auth_pae.eapolLogoff)
+ sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
+ }
+
+ SM_ENTRY(AUTH_PAE, RESTART, auth_pae);
+
+ sm->auth_pae.eapRestart = TRUE;
+ ieee802_1x_request_identity(sm->hapd, sm->sta);
+}
+
+
+SM_STATE(AUTH_PAE, CONNECTING)
+{
+ if (sm->auth_pae.state != AUTH_PAE_CONNECTING)
+ sm->auth_pae.authEntersConnecting++;
+
+ SM_ENTRY(AUTH_PAE, CONNECTING, auth_pae);
+
+ sm->reAuthenticate = FALSE;
+ sm->auth_pae.reAuthCount++;
+}
+
+
+SM_STATE(AUTH_PAE, HELD)
+{
+ if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authFail)
+ sm->auth_pae.authAuthFailWhileAuthenticating++;
+
+ SM_ENTRY(AUTH_PAE, HELD, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->quietWhile = sm->auth_pae.quietPeriod;
+ sm->auth_pae.eapolLogoff = FALSE;
+
+ hostapd_logger(sm->hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_WARNING, "authentication failed");
+ if (sm->flags & EAPOL_SM_PREAUTH)
+ rsn_preauth_finished(sm->hapd, sm->sta, 0);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATED)
+{
+ if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
+ sm->auth_pae.authAuthSuccessesWhileAuthenticating++;
+
+ SM_ENTRY(AUTH_PAE, AUTHENTICATED, auth_pae);
+
+ sm->authPortStatus = Authorized;
+ setPortAuthorized();
+ sm->auth_pae.reAuthCount = 0;
+ hostapd_logger(sm->hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO, "authenticated");
+ if (sm->flags & EAPOL_SM_PREAUTH)
+ rsn_preauth_finished(sm->hapd, sm->sta, 1);
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATING)
+{
+ if (sm->auth_pae.state == AUTH_PAE_CONNECTING && sm->rx_identity) {
+ sm->auth_pae.authEntersAuthenticating++;
+ sm->rx_identity = FALSE;
+ }
+
+ SM_ENTRY(AUTH_PAE, AUTHENTICATING, auth_pae);
+
+ sm->auth_pae.eapolStart = FALSE;
+ sm->authSuccess = FALSE;
+ sm->authFail = FALSE;
+ sm->authTimeout = FALSE;
+ sm->authStart = TRUE;
+ sm->keyRun = FALSE;
+ sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, ABORTING)
+{
+ if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING) {
+ if (sm->authTimeout)
+ sm->auth_pae.authAuthTimeoutsWhileAuthenticating++;
+ if (sm->auth_pae.eapolStart)
+ sm->auth_pae.authAuthEapStartsWhileAuthenticating++;
+ if (sm->auth_pae.eapolLogoff)
+ sm->auth_pae.authAuthEapLogoffWhileAuthenticating++;
+ }
+
+ SM_ENTRY(AUTH_PAE, ABORTING, auth_pae);
+
+ sm->authAbort = TRUE;
+ sm->keyRun = FALSE;
+ sm->keyDone = FALSE;
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_AUTH)
+{
+ SM_ENTRY(AUTH_PAE, FORCE_AUTH, auth_pae);
+
+ sm->authPortStatus = Authorized;
+ setPortAuthorized();
+ sm->auth_pae.portMode = ForceAuthorized;
+ sm->auth_pae.eapolStart = FALSE;
+ txCannedSuccess();
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_UNAUTH)
+{
+ SM_ENTRY(AUTH_PAE, FORCE_UNAUTH, auth_pae);
+
+ sm->authPortStatus = Unauthorized;
+ setPortUnauthorized();
+ sm->auth_pae.portMode = ForceUnauthorized;
+ sm->auth_pae.eapolStart = FALSE;
+ txCannedFail();
+}
+
+
+SM_STEP(AUTH_PAE)
+{
+ if ((sm->portControl == Auto &&
+ sm->auth_pae.portMode != sm->portControl) ||
+ sm->initialize || !sm->portEnabled)
+ SM_ENTER(AUTH_PAE, INITIALIZE);
+ else if (sm->portControl == ForceAuthorized &&
+ sm->auth_pae.portMode != sm->portControl &&
+ !(sm->initialize || !sm->portEnabled))
+ SM_ENTER(AUTH_PAE, FORCE_AUTH);
+ else if (sm->portControl == ForceUnauthorized &&
+ sm->auth_pae.portMode != sm->portControl &&
+ !(sm->initialize || !sm->portEnabled))
+ SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+ else {
+ switch (sm->auth_pae.state) {
+ case AUTH_PAE_INITIALIZE:
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ break;
+ case AUTH_PAE_DISCONNECTED:
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_RESTART:
+ if (!sm->auth_pae.eapRestart)
+ SM_ENTER(AUTH_PAE, CONNECTING);
+ break;
+ case AUTH_PAE_HELD:
+ if (sm->quietWhile == 0)
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_CONNECTING:
+ if (sm->auth_pae.eapolLogoff ||
+ sm->auth_pae.reAuthCount > sm->auth_pae.reAuthMax)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ else if ((sm->be_auth.eapReq &&
+ sm->auth_pae.reAuthCount <=
+ sm->auth_pae.reAuthMax) ||
+ sm->eapSuccess || sm->eapFail)
+ SM_ENTER(AUTH_PAE, AUTHENTICATING);
+ break;
+ case AUTH_PAE_AUTHENTICATED:
+ if (sm->auth_pae.eapolStart || sm->reAuthenticate)
+ SM_ENTER(AUTH_PAE, RESTART);
+ else if (sm->auth_pae.eapolLogoff || !sm->portValid)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ break;
+ case AUTH_PAE_AUTHENTICATING:
+ if (sm->authSuccess && sm->portValid)
+ SM_ENTER(AUTH_PAE, AUTHENTICATED);
+ else if (sm->authFail ||
+ (sm->keyDone && !sm->portValid))
+ SM_ENTER(AUTH_PAE, HELD);
+ else if (sm->auth_pae.eapolStart ||
+ sm->auth_pae.eapolLogoff || sm->authTimeout)
+ SM_ENTER(AUTH_PAE, ABORTING);
+ break;
+ case AUTH_PAE_ABORTING:
+ if (sm->auth_pae.eapolLogoff && !sm->authAbort)
+ SM_ENTER(AUTH_PAE, DISCONNECTED);
+ else if (!sm->auth_pae.eapolLogoff && !sm->authAbort)
+ SM_ENTER(AUTH_PAE, RESTART);
+ break;
+ case AUTH_PAE_FORCE_AUTH:
+ if (sm->auth_pae.eapolStart)
+ SM_ENTER(AUTH_PAE, FORCE_AUTH);
+ break;
+ case AUTH_PAE_FORCE_UNAUTH:
+ if (sm->auth_pae.eapolStart)
+ SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+ break;
+ }
+ }
+}
+
+
+
+/* Backend Authentication state machine */
+
+SM_STATE(BE_AUTH, INITIALIZE)
+{
+ SM_ENTRY(BE_AUTH, INITIALIZE, be_auth);
+
+ abortAuth();
+ sm->be_auth.eapNoReq = FALSE;
+ sm->authAbort = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, REQUEST)
+{
+ SM_ENTRY(BE_AUTH, REQUEST, be_auth);
+
+ txReq();
+ sm->be_auth.eapReq = FALSE;
+ sm->be_auth.backendOtherRequestsToSupplicant++;
+}
+
+
+SM_STATE(BE_AUTH, RESPONSE)
+{
+ SM_ENTRY(BE_AUTH, RESPONSE, be_auth);
+
+ sm->authTimeout = FALSE;
+ sm->eapolEap = FALSE;
+ sm->be_auth.eapNoReq = FALSE;
+ sm->aWhile = sm->be_auth.serverTimeout;
+ sm->be_auth.eapResp = TRUE;
+ sendRespToServer();
+ sm->be_auth.backendResponses++;
+}
+
+
+SM_STATE(BE_AUTH, SUCCESS)
+{
+ SM_ENTRY(BE_AUTH, SUCCESS, be_auth);
+
+ txReq();
+ sm->authSuccess = TRUE;
+ sm->keyRun = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, FAIL)
+{
+ SM_ENTRY(BE_AUTH, FAIL, be_auth);
+
+ /* Note: IEEE 802.1X-REV-d11 has unconditional txReq() here.
+ * txCannelFail() is used as a workaround for the case where
+ * authentication server does not include EAP-Message with
+ * Access-Reject. */
+ if (sm->last_eap_radius == NULL)
+ txCannedFail();
+ else
+ txReq();
+ sm->authFail = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, TIMEOUT)
+{
+ SM_ENTRY(BE_AUTH, TIMEOUT, be_auth);
+
+ sm->authTimeout = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, IDLE)
+{
+ SM_ENTRY(BE_AUTH, IDLE, be_auth);
+
+ sm->authStart = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, IGNORE)
+{
+ SM_ENTRY(BE_AUTH, IGNORE, be_auth);
+
+ sm->be_auth.eapNoReq = FALSE;
+}
+
+
+SM_STEP(BE_AUTH)
+{
+ if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
+ SM_ENTER(BE_AUTH, INITIALIZE);
+ return;
+ }
+
+ switch (sm->be_auth.state) {
+ case BE_AUTH_INITIALIZE:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_REQUEST:
+ if (sm->eapolEap)
+ SM_ENTER(BE_AUTH, RESPONSE);
+ else if (sm->be_auth.eapReq)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eapTimeout)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ break;
+ case BE_AUTH_RESPONSE:
+ if (sm->be_auth.eapNoReq)
+ SM_ENTER(BE_AUTH, IGNORE);
+ if (sm->be_auth.eapReq) {
+ sm->be_auth.backendAccessChallenges++;
+ SM_ENTER(BE_AUTH, REQUEST);
+ } else if (sm->aWhile == 0)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ else if (sm->eapFail) {
+ sm->be_auth.backendAuthFails++;
+ SM_ENTER(BE_AUTH, FAIL);
+ } else if (sm->eapSuccess) {
+ sm->be_auth.backendAuthSuccesses++;
+ SM_ENTER(BE_AUTH, SUCCESS);
+ }
+ break;
+ case BE_AUTH_SUCCESS:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_FAIL:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_TIMEOUT:
+ SM_ENTER(BE_AUTH, IDLE);
+ break;
+ case BE_AUTH_IDLE:
+ if (sm->eapFail && sm->authStart)
+ SM_ENTER(BE_AUTH, FAIL);
+ else if (sm->be_auth.eapReq && sm->authStart)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eapSuccess && sm->authStart)
+ SM_ENTER(BE_AUTH, SUCCESS);
+ break;
+ case BE_AUTH_IGNORE:
+ if (sm->eapolEap)
+ SM_ENTER(BE_AUTH, RESPONSE);
+ else if (sm->be_auth.eapReq)
+ SM_ENTER(BE_AUTH, REQUEST);
+ else if (sm->eapTimeout)
+ SM_ENTER(BE_AUTH, TIMEOUT);
+ break;
+ }
+}
+
+
+
+/* Reauthentication Timer state machine */
+
+SM_STATE(REAUTH_TIMER, INITIALIZE)
+{
+ SM_ENTRY(REAUTH_TIMER, INITIALIZE, reauth_timer);
+
+ sm->reAuthWhen = sm->reauth_timer.reAuthPeriod;
+}
+
+
+SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
+{
+ SM_ENTRY(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
+
+ sm->reAuthenticate = TRUE;
+ wpa_sm_event(sm->hapd, sm->sta, WPA_REAUTH_EAPOL);
+}
+
+
+SM_STEP(REAUTH_TIMER)
+{
+ if (sm->portControl != Auto || sm->initialize ||
+ sm->authPortStatus == Unauthorized ||
+ !sm->reauth_timer.reAuthEnabled) {
+ SM_ENTER(REAUTH_TIMER, INITIALIZE);
+ return;
+ }
+
+ switch (sm->reauth_timer.state) {
+ case REAUTH_TIMER_INITIALIZE:
+ if (sm->reAuthWhen == 0)
+ SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
+ break;
+ case REAUTH_TIMER_REAUTHENTICATE:
+ SM_ENTER(REAUTH_TIMER, INITIALIZE);
+ break;
+ }
+}
+
+
+
+/* Authenticator Key Transmit state machine */
+
+SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
+{
+ SM_ENTRY(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
+}
+
+
+SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
+{
+ SM_ENTRY(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
+
+ txKey();
+ sm->keyAvailable = FALSE;
+ sm->keyDone = TRUE;
+}
+
+
+SM_STEP(AUTH_KEY_TX)
+{
+ if (sm->initialize || sm->portControl != Auto) {
+ SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+ return;
+ }
+
+ switch (sm->auth_key_tx.state) {
+ case AUTH_KEY_TX_NO_KEY_TRANSMIT:
+ if (sm->keyTxEnabled && sm->keyAvailable && sm->keyRun &&
+ !sm->sta->wpa)
+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+ break;
+ case AUTH_KEY_TX_KEY_TRANSMIT:
+ if (!sm->keyTxEnabled || !sm->keyRun)
+ SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+ else if (sm->keyAvailable)
+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+ break;
+ }
+}
+
+
+
+/* Key Receive state machine */
+
+SM_STATE(KEY_RX, NO_KEY_RECEIVE)
+{
+ SM_ENTRY(KEY_RX, NO_KEY_RECEIVE, key_rx);
+}
+
+
+SM_STATE(KEY_RX, KEY_RECEIVE)
+{
+ SM_ENTRY(KEY_RX, KEY_RECEIVE, key_rx);
+
+ processKey();
+ sm->key_rx.rxKey = FALSE;
+}
+
+
+SM_STEP(KEY_RX)
+{
+ if (sm->initialize || !sm->portEnabled) {
+ SM_ENTER(KEY_RX, NO_KEY_RECEIVE);
+ return;
+ }
+
+ switch (sm->key_rx.state) {
+ case KEY_RX_NO_KEY_RECEIVE:
+ if (sm->key_rx.rxKey)
+ SM_ENTER(KEY_RX, KEY_RECEIVE);
+ break;
+ case KEY_RX_KEY_RECEIVE:
+ if (sm->key_rx.rxKey)
+ SM_ENTER(KEY_RX, KEY_RECEIVE);
+ break;
+ }
+}
+
+
+
+/* Controlled Directions state machine */
+
+SM_STATE(CTRL_DIR, FORCE_BOTH)
+{
+ SM_ENTRY(CTRL_DIR, FORCE_BOTH, ctrl_dir);
+ sm->ctrl_dir.operControlledDirections = Both;
+}
+
+
+SM_STATE(CTRL_DIR, IN_OR_BOTH)
+{
+ SM_ENTRY(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
+ sm->ctrl_dir.operControlledDirections =
+ sm->ctrl_dir.adminControlledDirections;
+}
+
+
+SM_STEP(CTRL_DIR)
+{
+ if (sm->initialize) {
+ SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+ return;
+ }
+
+ switch (sm->ctrl_dir.state) {
+ case CTRL_DIR_FORCE_BOTH:
+ if (sm->portEnabled && sm->ctrl_dir.operEdge)
+ SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+ break;
+ case CTRL_DIR_IN_OR_BOTH:
+ if (sm->ctrl_dir.operControlledDirections !=
+ sm->ctrl_dir.adminControlledDirections)
+ SM_ENTER(CTRL_DIR, IN_OR_BOTH);
+ if (!sm->portEnabled || !sm->ctrl_dir.operEdge)
+ SM_ENTER(CTRL_DIR, FORCE_BOTH);
+ break;
+ }
+}
+
+
+
+struct eapol_state_machine *
+eapol_sm_alloc(hostapd *hapd, struct sta_info *sta)
+{
+ struct eapol_state_machine *sm;
+
+ sm = (struct eapol_state_machine *) malloc(sizeof(*sm));
+ if (sm == NULL) {
+ printf("IEEE 802.1X port state allocation failed\n");
+ return NULL;
+ }
+ memset(sm, 0, sizeof(*sm));
+ sm->radius_identifier = -1;
+ memcpy(sm->addr, sta->addr, ETH_ALEN);
+ if (sta->flags & WLAN_STA_PREAUTH)
+ sm->flags |= EAPOL_SM_PREAUTH;
+
+ sm->hapd = hapd;
+ sm->sta = sta;
+
+ /* Set default values for state machine constants */
+ sm->auth_pae.state = AUTH_PAE_INITIALIZE;
+ sm->auth_pae.quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
+ sm->auth_pae.reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
+
+ sm->be_auth.state = BE_AUTH_INITIALIZE;
+ sm->be_auth.serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
+
+ sm->reauth_timer.state = REAUTH_TIMER_INITIALIZE;
+ sm->reauth_timer.reAuthPeriod = hapd->conf->eap_reauth_period;
+ sm->reauth_timer.reAuthEnabled = hapd->conf->eap_reauth_period > 0 ?
+ TRUE : FALSE;
+
+ sm->auth_key_tx.state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
+
+ sm->key_rx.state = KEY_RX_NO_KEY_RECEIVE;
+
+ sm->ctrl_dir.state = CTRL_DIR_IN_OR_BOTH;
+
+ sm->portEnabled = FALSE;
+ sm->portControl = Auto;
+
+ sm->keyAvailable = FALSE;
+ if (!hapd->conf->wpa &&
+ (hapd->default_wep_key || hapd->conf->individual_wep_key_len > 0))
+ sm->keyTxEnabled = TRUE;
+ else
+ sm->keyTxEnabled = FALSE;
+ if (hapd->conf->wpa)
+ sm->portValid = FALSE;
+ else
+ sm->portValid = TRUE;
+
+ if (hapd->conf->eap_authenticator) {
+ struct eap_config eap_conf;
+ memset(&eap_conf, 0, sizeof(eap_conf));
+ eap_conf.ssl_ctx = hapd->ssl_ctx;
+ eap_conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+ sm->eap = eap_sm_init(sm, &eapol_cb, &eap_conf);
+ if (sm->eap == NULL) {
+ eapol_sm_free(sm);
+ return NULL;
+ }
+ }
+
+ eapol_sm_initialize(sm);
+
+ return sm;
+}
+
+
+void eapol_sm_free(struct eapol_state_machine *sm)
+{
+ if (sm == NULL)
+ return;
+
+ eloop_cancel_timeout(eapol_port_timers_tick, sm->hapd, sm);
+ if (sm->eap)
+ eap_sm_deinit(sm->eap);
+ free(sm);
+}
+
+
+static int eapol_sm_sta_entry_alive(struct hostapd_data *hapd, u8 *addr)
+{
+ struct sta_info *sta;
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL || sta->eapol_sm == NULL)
+ return 0;
+ return 1;
+}
+
+
+void eapol_sm_step(struct eapol_state_machine *sm)
+{
+ struct hostapd_data *hapd = sm->hapd;
+ u8 addr[ETH_ALEN];
+ int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx,
+ prev_key_rx, prev_ctrl_dir;
+
+ /* FIX: could re-run eapol_sm_step from registered timeout (after
+ * 0 sec) to make sure that other possible timeouts/events are
+ * processed */
+
+ memcpy(addr, sm->sta->addr, ETH_ALEN);
+restart:
+ do {
+ prev_auth_pae = sm->auth_pae.state;
+ prev_be_auth = sm->be_auth.state;
+ prev_reauth_timer = sm->reauth_timer.state;
+ prev_auth_key_tx = sm->auth_key_tx.state;
+ prev_key_rx = sm->key_rx.state;
+ prev_ctrl_dir = sm->ctrl_dir.state;
+
+ SM_STEP_RUN(AUTH_PAE);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ SM_STEP_RUN(BE_AUTH);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ SM_STEP_RUN(REAUTH_TIMER);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ SM_STEP_RUN(AUTH_KEY_TX);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ SM_STEP_RUN(KEY_RX);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ SM_STEP_RUN(CTRL_DIR);
+ if (!eapol_sm_sta_entry_alive(hapd, addr))
+ break;
+ } while (prev_auth_pae != sm->auth_pae.state ||
+ prev_be_auth != sm->be_auth.state ||
+ prev_reauth_timer != sm->reauth_timer.state ||
+ prev_auth_key_tx != sm->auth_key_tx.state ||
+ prev_key_rx != sm->key_rx.state ||
+ prev_ctrl_dir != sm->ctrl_dir.state);
+
+ if (eapol_sm_sta_entry_alive(hapd, addr) && sm->eap) {
+ if (eap_sm_step(sm->eap))
+ goto restart;
+ }
+
+ if (eapol_sm_sta_entry_alive(hapd, addr))
+ wpa_sm_notify(sm->hapd, sm->sta);
+}
+
+
+void eapol_sm_initialize(struct eapol_state_machine *sm)
+{
+ /* Initialize the state machines by asserting initialize and then
+ * deasserting it after one step */
+ sm->initialize = TRUE;
+ eapol_sm_step(sm);
+ sm->initialize = FALSE;
+ eapol_sm_step(sm);
+
+ /* Start one second tick for port timers state machine */
+ eloop_cancel_timeout(eapol_port_timers_tick, sm->hapd, sm);
+ eloop_register_timeout(1, 0, eapol_port_timers_tick, sm->hapd, sm);
+}
+
+
+#ifdef HOSTAPD_DUMP_STATE
+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_sm_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->eapFail), _SB(sm->eapolEap),
+ prefix, _SB(sm->eapSuccess), _SB(sm->eapTimeout),
+ _SB(sm->initialize), _SB(sm->keyAvailable),
+ prefix, _SB(sm->keyDone), _SB(sm->keyRun),
+ _SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
+ prefix, _SB(sm->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->auth_pae.eapolLogoff), _SB(sm->auth_pae.eapolStart),
+ _SB(sm->auth_pae.eapRestart), prefix,
+ port_type_txt(sm->auth_pae.portMode), sm->auth_pae.reAuthCount,
+ prefix, sm->auth_pae.quietPeriod, sm->auth_pae.reAuthMax,
+ prefix, sm->auth_pae.authEntersConnecting,
+ prefix, sm->auth_pae.authEapLogoffsWhileConnecting,
+ prefix, sm->auth_pae.authEntersAuthenticating,
+ prefix, sm->auth_pae.authAuthSuccessesWhileAuthenticating,
+ prefix, sm->auth_pae.authAuthTimeoutsWhileAuthenticating,
+ prefix, sm->auth_pae.authAuthFailWhileAuthenticating,
+ prefix, sm->auth_pae.authAuthEapStartsWhileAuthenticating,
+ prefix, sm->auth_pae.authAuthEapLogoffWhileAuthenticating,
+ prefix, sm->auth_pae.authAuthReauthsWhileAuthenticated,
+ prefix, sm->auth_pae.authAuthEapStartsWhileAuthenticated,
+ prefix, sm->auth_pae.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->be_auth.eapNoReq), _SB(sm->be_auth.eapReq),
+ _SB(sm->be_auth.eapResp),
+ prefix, sm->be_auth.serverTimeout,
+ prefix, sm->be_auth.backendResponses,
+ prefix, sm->be_auth.backendAccessChallenges,
+ prefix, sm->be_auth.backendOtherRequestsToSupplicant,
+ prefix, sm->be_auth.backendAuthSuccesses,
+ prefix, sm->be_auth.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->reauth_timer.reAuthPeriod,
+ _SB(sm->reauth_timer.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->key_rx.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->ctrl_dir.adminControlledDirections),
+ ctrl_dir_txt(sm->ctrl_dir.operControlledDirections),
+ prefix, _SB(sm->ctrl_dir.operEdge));
+#undef _SB
+}
+#endif /* HOSTAPD_DUMP_STATE */
+
+
+static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+ struct eapol_state_machine *sm = ctx;
+ if (sm == NULL)
+ return FALSE;
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ return sm->eapSuccess;
+ case EAPOL_eapRestart:
+ return sm->auth_pae.eapRestart;
+ case EAPOL_eapFail:
+ return sm->eapFail;
+ case EAPOL_eapResp:
+ return sm->be_auth.eapResp;
+ case EAPOL_eapReq:
+ return sm->be_auth.eapReq;
+ case EAPOL_eapNoReq:
+ return sm->be_auth.eapNoReq;
+ case EAPOL_portEnabled:
+ return sm->portEnabled;
+ case EAPOL_eapTimeout:
+ return sm->eapTimeout;
+ }
+ return FALSE;
+}
+
+
+static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
+ Boolean value)
+{
+ struct eapol_state_machine *sm = ctx;
+ if (sm == NULL)
+ return;
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ sm->eapSuccess = value;
+ break;
+ case EAPOL_eapRestart:
+ sm->auth_pae.eapRestart = value;
+ break;
+ case EAPOL_eapFail:
+ sm->eapFail = value;
+ break;
+ case EAPOL_eapResp:
+ sm->be_auth.eapResp = value;
+ break;
+ case EAPOL_eapReq:
+ sm->be_auth.eapReq = value;
+ break;
+ case EAPOL_eapNoReq:
+ sm->be_auth.eapNoReq = value;
+ break;
+ case EAPOL_portEnabled:
+ sm->portEnabled = value;
+ break;
+ case EAPOL_eapTimeout:
+ sm->eapTimeout = value;
+ break;
+ }
+}
+
+
+static void eapol_sm_set_eapReqData(void *ctx, const u8 *eapReqData,
+ size_t eapReqDataLen)
+{
+ struct eapol_state_machine *sm = ctx;
+ if (sm == NULL)
+ return;
+
+ free(sm->last_eap_radius);
+ sm->last_eap_radius = malloc(eapReqDataLen);
+ if (sm->last_eap_radius == NULL)
+ return;
+ memcpy(sm->last_eap_radius, eapReqData, eapReqDataLen);
+ sm->last_eap_radius_len = eapReqDataLen;
+}
+
+
+static void eapol_sm_set_eapKeyData(void *ctx, const u8 *eapKeyData,
+ size_t eapKeyDataLen)
+{
+ struct eapol_state_machine *sm = ctx;
+ struct hostapd_data *hapd;
+
+ if (sm == NULL)
+ return;
+
+ hapd = sm->hapd;
+
+ if (eapKeyData && eapKeyDataLen >= 64) {
+ free(sm->eapol_key_sign);
+ free(sm->eapol_key_crypt);
+ sm->eapol_key_crypt = malloc(32);
+ if (sm->eapol_key_crypt) {
+ memcpy(sm->eapol_key_crypt, eapKeyData, 32);
+ sm->eapol_key_crypt_len = 32;
+ }
+ sm->eapol_key_sign = malloc(32);
+ if (sm->eapol_key_sign) {
+ memcpy(sm->eapol_key_sign, eapKeyData + 32, 32);
+ sm->eapol_key_sign_len = 32;
+ }
+ if (hapd->default_wep_key ||
+ hapd->conf->individual_wep_key_len > 0 ||
+ hapd->conf->wpa)
+ sm->keyAvailable = TRUE;
+ } else {
+ free(sm->eapol_key_sign);
+ free(sm->eapol_key_crypt);
+ sm->eapol_key_sign = NULL;
+ sm->eapol_key_crypt = NULL;
+ sm->eapol_key_sign_len = 0;
+ sm->eapol_key_crypt_len = 0;
+ sm->keyAvailable = FALSE;
+ }
+}
+
+
+static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct eapol_state_machine *sm = ctx;
+ const struct hostapd_eap_user *eap_user;
+
+ eap_user = hostapd_get_eap_user(sm->hapd->conf, identity,
+ identity_len, phase2);
+ if (eap_user == NULL)
+ return -1;
+
+ memset(user, 0, sizeof(*user));
+ user->phase2 = phase2;
+ memcpy(user->methods, eap_user->methods,
+ EAP_USER_MAX_METHODS > EAP_MAX_METHODS ?
+ EAP_USER_MAX_METHODS : EAP_MAX_METHODS);
+
+ if (eap_user->password) {
+ user->password = malloc(eap_user->password_len);
+ if (user->password == NULL)
+ return -1;
+ memcpy(user->password, eap_user->password,
+ eap_user->password_len);
+ user->password_len = eap_user->password_len;
+ }
+ user->force_version = eap_user->force_version;
+
+ return 0;
+}
+
+
+static struct eapol_callbacks eapol_cb =
+{
+ .get_bool = eapol_sm_get_bool,
+ .set_bool = eapol_sm_set_bool,
+ .set_eapReqData = eapol_sm_set_eapReqData,
+ .set_eapKeyData = eapol_sm_set_eapKeyData,
+ .get_eap_user = eapol_sm_get_eap_user,
+};
diff --git a/contrib/hostapd/eapol_sm.h b/contrib/hostapd/eapol_sm.h
new file mode 100644
index 000000000000..7b74ed1c607a
--- /dev/null
+++ b/contrib/hostapd/eapol_sm.h
@@ -0,0 +1,213 @@
+#ifndef EAPOL_SM_H
+#define EAPOL_SM_H
+
+#include "defs.h"
+
+/* IEEE Std 802.1X-REV-d11, Ch. 8.2 */
+
+typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
+ PortTypes;
+typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
+typedef enum { Both = 0, In = 1 } ControlledDirection;
+typedef unsigned int Counter;
+
+
+/* Authenticator PAE state machine */
+struct eapol_auth_pae_sm {
+ /* variables */
+ Boolean eapolLogoff;
+ Boolean eapolStart;
+ Boolean eapRestart;
+ PortTypes portMode;
+ unsigned int reAuthCount;
+
+ /* constants */
+ unsigned int quietPeriod; /* default 60; 0..65535 */
+#define AUTH_PAE_DEFAULT_quietPeriod 60
+ unsigned int reAuthMax; /* default 2 */
+#define AUTH_PAE_DEFAULT_reAuthMax 2
+
+ /* counters */
+ Counter authEntersConnecting;
+ Counter authEapLogoffsWhileConnecting;
+ Counter authEntersAuthenticating;
+ Counter authAuthSuccessesWhileAuthenticating;
+ Counter authAuthTimeoutsWhileAuthenticating;
+ Counter authAuthFailWhileAuthenticating;
+ Counter authAuthEapStartsWhileAuthenticating;
+ Counter authAuthEapLogoffWhileAuthenticating;
+ Counter authAuthReauthsWhileAuthenticated;
+ Counter authAuthEapStartsWhileAuthenticated;
+ Counter authAuthEapLogoffWhileAuthenticated;
+
+ enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
+ AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
+ AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
+ AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } state;
+};
+
+
+/* Backend Authentication state machine */
+struct eapol_backend_auth_sm {
+ /* variables */
+ Boolean eapNoReq;
+ Boolean eapReq;
+ Boolean eapResp;
+
+ /* constants */
+ unsigned int serverTimeout; /* default 30; 1..X */
+#define BE_AUTH_DEFAULT_serverTimeout 30
+
+ /* counters */
+ Counter backendResponses;
+ Counter backendAccessChallenges;
+ Counter backendOtherRequestsToSupplicant;
+ Counter backendAuthSuccesses;
+ Counter backendAuthFails;
+
+ enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
+ BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
+ BE_AUTH_IGNORE
+ } state;
+};
+
+
+/* Reauthentication Timer state machine */
+struct eapol_reauth_timer_sm {
+ /* constants */
+ unsigned int reAuthPeriod; /* default 3600 s */
+ Boolean reAuthEnabled;
+
+ enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE } state;
+};
+
+
+/* Authenticator Key Transmit state machine */
+struct eapol_auth_key_tx {
+ enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT } state;
+};
+
+
+/* Key Receive state machine */
+struct eapol_key_rx {
+ /* variables */
+ Boolean rxKey;
+
+ enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } state;
+};
+
+
+/* Controlled Directions state machine */
+struct eapol_ctrl_dir {
+ /* variables */
+ ControlledDirection adminControlledDirections;
+ ControlledDirection operControlledDirections;
+ Boolean operEdge;
+
+ enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } state;
+};
+
+
+struct eap_sm;
+
+struct eapol_state_machine {
+ /* timers */
+ int aWhile;
+ int quietWhile;
+ int reAuthWhen;
+
+ /* global variables */
+ Boolean authAbort;
+ Boolean authFail;
+ PortState authPortStatus;
+ Boolean authStart;
+ Boolean authTimeout;
+ Boolean authSuccess;
+ Boolean eapFail;
+ Boolean eapolEap;
+ Boolean eapSuccess;
+ Boolean eapTimeout;
+ Boolean initialize;
+ Boolean keyAvailable;
+ Boolean keyDone;
+ Boolean keyRun;
+ Boolean keyTxEnabled;
+ PortTypes portControl;
+ Boolean portEnabled;
+ Boolean portValid;
+ Boolean reAuthenticate;
+
+ /* Port Timers state machine */
+ /* 'Boolean tick' implicitly handled as registered timeout */
+
+ struct eapol_auth_pae_sm auth_pae;
+ struct eapol_backend_auth_sm be_auth;
+ struct eapol_reauth_timer_sm reauth_timer;
+ struct eapol_auth_key_tx auth_key_tx;
+ struct eapol_key_rx key_rx;
+ struct eapol_ctrl_dir ctrl_dir;
+
+ /* Authenticator Statistics Table */
+ Counter dot1xAuthEapolFramesRx;
+ Counter dot1xAuthEapolFramesTx;
+ Counter dot1xAuthEapolStartFramesRx;
+ Counter dot1xAuthEapolLogoffFramesRx;
+ Counter dot1xAuthEapolRespIdFramesRx;
+ Counter dot1xAuthEapolRespFramesRx;
+ Counter dot1xAuthEapolReqIdFramesTx;
+ Counter dot1xAuthEapolReqFramesTx;
+ Counter dot1xAuthInvalidEapolFramesRx;
+ Counter dot1xAuthEapLengthErrorFramesRx;
+ Counter dot1xAuthLastEapolFrameVersion;
+
+ /* Other variables - not defined in IEEE 802.1X */
+ u8 addr[ETH_ALEN]; /* Supplicant address */
+#define EAPOL_SM_PREAUTH BIT(0)
+ int flags; /* EAPOL_SM_* */
+
+ int radius_identifier;
+ /* TODO: check when the last messages can be released */
+ struct radius_msg *last_recv_radius;
+ u8 *last_eap_supp; /* last received EAP Response from Supplicant */
+ size_t last_eap_supp_len;
+ u8 *last_eap_radius; /* last received EAP Response from Authentication
+ * Server */
+ size_t last_eap_radius_len;
+ u8 *identity;
+ size_t identity_len;
+ u8 *radius_class;
+ size_t radius_class_len;
+
+ /* Keys for encrypting and signing EAPOL-Key frames */
+ u8 *eapol_key_sign;
+ size_t eapol_key_sign_len;
+ u8 *eapol_key_crypt;
+ size_t eapol_key_crypt_len;
+
+ Boolean rx_identity; /* set to TRUE on reception of
+ * EAP-Response/Identity */
+
+ struct eap_sm *eap;
+
+ /* currentId was removed in IEEE 802.1X-REV, but it is needed to filter
+ * out EAP-Responses to old packets (e.g., to two EAP-Request/Identity
+ * packets that are often sent in the beginning of the authentication).
+ */
+ u8 currentId;
+
+ /* Somewhat nasty pointers to global hostapd and STA data to avoid
+ * passing these to every function */
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+};
+
+
+struct eapol_state_machine *eapol_sm_alloc(hostapd *hapd,
+ struct sta_info *sta);
+void eapol_sm_free(struct eapol_state_machine *sm);
+void eapol_sm_step(struct eapol_state_machine *sm);
+void eapol_sm_initialize(struct eapol_state_machine *sm);
+void eapol_sm_dump_state(FILE *f, const char *prefix,
+ struct eapol_state_machine *sm);
+
+#endif /* EAPOL_SM_H */
diff --git a/contrib/hostapd/eloop.c b/contrib/hostapd/eloop.c
new file mode 100644
index 000000000000..60715089beb2
--- /dev/null
+++ b/contrib/hostapd/eloop.c
@@ -0,0 +1,380 @@
+/*
+ * Event loop
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include "common.h"
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+ struct timeval time;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(void *eloop_ctx, void *sock_ctx);
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ int signaled;
+};
+
+struct eloop_data {
+ void *user_data;
+
+ int max_sock, reader_count;
+ struct eloop_sock *readers;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+};
+
+static struct eloop_data eloop;
+
+
+void eloop_init(void *user_data)
+{
+ memset(&eloop, 0, sizeof(eloop));
+ eloop.user_data = user_data;
+}
+
+
+int eloop_register_read_sock(int sock,
+ void (*handler)(int sock, void *eloop_ctx,
+ void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock *tmp;
+
+ tmp = (struct eloop_sock *)
+ realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ int i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+ if (i != eloop.reader_count - 1) {
+ memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ gettimeofday(&timeout->time, NULL);
+ timeout->time.tv_sec += secs;
+ timeout->time.tv_usec += usecs;
+ while (timeout->time.tv_usec >= 1000000) {
+ timeout->time.tv_sec++;
+ timeout->time.tv_usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (timercmp(&timeout->time, &tmp->time, <))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(int sig)
+{
+ fprintf(stderr, "eloop: could not process SIGINT or SIGTERM in two "
+ "seconds. Looks like there\n"
+ "is a bug that ends up in a busy loop that "
+ "prevents clean shutdown.\n"
+ "Killing program forcefully.\n");
+ exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+ /* Use SIGALRM to break out from potential busy loops that
+ * would not allow the program to be killed. */
+ eloop.pending_terminate = 1;
+ signal(SIGALRM, eloop_handle_alarm);
+ alarm(2);
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+ alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+}
+
+
+int eloop_register_signal(int sig,
+ void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = (struct eloop_signal *)
+ realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+ signal(sig, eloop_handle_signal);
+
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ fd_set rfds;
+ int i, res;
+ struct timeval tv, now;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0)) {
+ if (eloop.timeout) {
+ gettimeofday(&now, NULL);
+ if (timercmp(&now, &eloop.timeout->time, <))
+ timersub(&eloop.timeout->time, &now, &tv);
+ else
+ tv.tv_sec = tv.tv_usec = 0;
+#if 0
+ printf("next timeout in %lu.%06lu sec\n",
+ tv.tv_sec, tv.tv_usec);
+#endif
+ }
+
+ FD_ZERO(&rfds);
+ for (i = 0; i < eloop.reader_count; i++)
+ FD_SET(eloop.readers[i].sock, &rfds);
+ res = select(eloop.max_sock + 1, &rfds, NULL, NULL,
+ eloop.timeout ? &tv : NULL);
+ if (res < 0 && errno != EINTR) {
+ perror("select");
+ return;
+ }
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ gettimeofday(&now, NULL);
+ if (!timercmp(&now, &eloop.timeout->time, <)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ free(tmp);
+ }
+
+ }
+
+ if (res <= 0)
+ continue;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (FD_ISSET(eloop.readers[i].sock, &rfds)) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ free(prev);
+ }
+ free(eloop.readers);
+ free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
diff --git a/contrib/hostapd/eloop.h b/contrib/hostapd/eloop.h
new file mode 100644
index 000000000000..f5b884740421
--- /dev/null
+++ b/contrib/hostapd/eloop.h
@@ -0,0 +1,53 @@
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/* Magic number for eloop_cancel_timeout() */
+#define ELOOP_ALL_CTX (void *) -1
+
+/* Initialize global event loop data - must be called before any other eloop_*
+ * function. user_data is a pointer to global data structure and will be passed
+ * as eloop_ctx to signal handlers. */
+void eloop_init(void *user_data);
+
+/* Register handler for read event */
+int eloop_register_read_sock(int sock,
+ void (*handler)(int sock, void *eloop_ctx,
+ void *sock_ctx),
+ void *eloop_data, void *user_data);
+void eloop_unregister_read_sock(int sock);
+
+/* Register timeout */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ void *eloop_data, void *user_data);
+
+/* Cancel timeouts matching <handler,eloop_data,user_data>.
+ * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
+ * regardless of eloop_data/user_data. */
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+ void *eloop_data, void *user_data);
+
+/* Register handler for signal.
+ * Note: signals are 'global' events and there is no local eloop_data pointer
+ * like with other handlers. The (global) pointer given to eloop_init() will be
+ * used as eloop_ctx for signal handlers. */
+int eloop_register_signal(int sock,
+ void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data);
+
+/* Start event loop and continue running as long as there are any registered
+ * event handlers. */
+void eloop_run(void);
+
+/* Terminate event loop even if there are registered events. */
+void eloop_terminate(void);
+
+/* Free any reserved resources. After calling eloop_destoy(), other eloop_*
+ * functions must not be called before re-running eloop_init(). */
+void eloop_destroy(void);
+
+/* Check whether event loop has been terminated. */
+int eloop_terminated(void);
+
+#endif /* ELOOP_H */
diff --git a/contrib/hostapd/hostap_common.h b/contrib/hostapd/hostap_common.h
new file mode 100644
index 000000000000..003ad9ac6b58
--- /dev/null
+++ b/contrib/hostapd/hostap_common.h
@@ -0,0 +1,557 @@
+#ifndef HOSTAP_COMMON_H
+#define HOSTAP_COMMON_H
+
+#define BIT(x) (1 << (x))
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+
+
+/* IEEE 802.11 defines */
+
+#define WLAN_FC_PVER (BIT(1) | BIT(0))
+#define WLAN_FC_TODS BIT(8)
+#define WLAN_FC_FROMDS BIT(9)
+#define WLAN_FC_MOREFRAG BIT(10)
+#define WLAN_FC_RETRY BIT(11)
+#define WLAN_FC_PWRMGT BIT(12)
+#define WLAN_FC_MOREDATA BIT(13)
+#define WLAN_FC_ISWEP BIT(14)
+#define WLAN_FC_ORDER BIT(15)
+
+#define WLAN_FC_GET_TYPE(fc) (((fc) & (BIT(3) | BIT(2))) >> 2)
+#define WLAN_FC_GET_STYPE(fc) \
+ (((fc) & (BIT(7) | BIT(6) | BIT(5) | BIT(4))) >> 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
+
+/* 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
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#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)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#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
+/* 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.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
+
+/* Reason codes */
+#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.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
+
+
+/* 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_CHALLENGE 16
+#define WLAN_EID_RSN 48
+#define WLAN_EID_GENERIC 221
+
+
+/* HFA384X Configuration RIDs */
+#define HFA384X_RID_CNFPORTTYPE 0xFC00
+#define HFA384X_RID_CNFOWNMACADDR 0xFC01
+#define HFA384X_RID_CNFDESIREDSSID 0xFC02
+#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
+#define HFA384X_RID_CNFOWNSSID 0xFC04
+#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
+#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
+#define HFA384X_RID_CNFMAXDATALEN 0xFC07
+#define HFA384X_RID_CNFWDSADDRESS 0xFC08
+#define HFA384X_RID_CNFPMENABLED 0xFC09
+#define HFA384X_RID_CNFPMEPS 0xFC0A
+#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
+#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
+#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
+#define HFA384X_RID_CNFOWNNAME 0xFC0E
+#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
+#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
+#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
+#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
+#define HFA384X_RID_UNKNOWN1 0xFC20
+#define HFA384X_RID_UNKNOWN2 0xFC21
+#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
+#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
+#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
+#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
+#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
+#define HFA384X_RID_CNFWEPFLAGS 0xFC28
+#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
+#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
+#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
+#define HFA384X_RID_CNFTXCONTROL 0xFC2C
+#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
+#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
+#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
+#define HFA384X_RID_CNFMMLIFE 0xFC31
+#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
+#define HFA384X_RID_CNFBEACONINT 0xFC33
+#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
+#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
+#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
+#define HFA384X_RID_CNFTIMCTRL 0xFC40
+#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
+#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
+#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
+#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
+ * write only */
+#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_GROUPADDRESSES 0xFC80
+#define HFA384X_RID_CREATEIBSS 0xFC81
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
+#define HFA384X_RID_RTSTHRESHOLD 0xFC83
+#define HFA384X_RID_TXRATECONTROL 0xFC84
+#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
+#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
+#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
+#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
+#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
+#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
+#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
+#define HFA384X_RID_CNFBASICRATES 0xFCB3
+#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
+#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
+#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
+#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
+#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
+#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
+#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
+#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
+#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_TICKTIME 0xFCE0
+#define HFA384X_RID_SCANREQUEST 0xFCE1
+#define HFA384X_RID_JOINREQUEST 0xFCE2
+#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
+#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
+#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
+
+/* HFA384X Information RIDs */
+#define HFA384X_RID_MAXLOADTIME 0xFD00
+#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
+#define HFA384X_RID_PRIID 0xFD02
+#define HFA384X_RID_PRISUPRANGE 0xFD03
+#define HFA384X_RID_CFIACTRANGES 0xFD04
+#define HFA384X_RID_NICSERNUM 0xFD0A
+#define HFA384X_RID_NICID 0xFD0B
+#define HFA384X_RID_MFISUPRANGE 0xFD0C
+#define HFA384X_RID_CFISUPRANGE 0xFD0D
+#define HFA384X_RID_CHANNELLIST 0xFD10
+#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
+#define HFA384X_RID_TEMPTYPE 0xFD12
+#define HFA384X_RID_CIS 0xFD13
+#define HFA384X_RID_STAID 0xFD20
+#define HFA384X_RID_STASUPRANGE 0xFD21
+#define HFA384X_RID_MFIACTRANGES 0xFD22
+#define HFA384X_RID_CFIACTRANGES2 0xFD23
+#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
+ * only Prism2.5(?) */
+#define HFA384X_RID_PORTSTATUS 0xFD40
+#define HFA384X_RID_CURRENTSSID 0xFD41
+#define HFA384X_RID_CURRENTBSSID 0xFD42
+#define HFA384X_RID_COMMSQUALITY 0xFD43
+#define HFA384X_RID_CURRENTTXRATE 0xFD44
+#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
+#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
+#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
+#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
+#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
+#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
+#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
+#define HFA384X_RID_CFPOLLABLE 0xFD4C
+#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
+#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
+#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
+#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
+#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
+#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
+#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
+#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
+#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
+#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
+#define HFA384X_RID_PHYTYPE 0xFDC0
+#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
+#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
+#define HFA384X_RID_CCAMODE 0xFDC3
+#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
+#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
+#define HFA384X_RID_BUILDSEQ 0xFFFE
+#define HFA384X_RID_FWID 0xFFFF
+
+
+struct hfa384x_comp_ident
+{
+ u16 id;
+ u16 variant;
+ u16 major;
+ u16 minor;
+} __attribute__ ((packed));
+
+#define HFA384X_COMP_ID_PRI 0x15
+#define HFA384X_COMP_ID_STA 0x1f
+#define HFA384X_COMP_ID_FW_AP 0x14b
+
+struct hfa384x_sup_range
+{
+ u16 role;
+ u16 id;
+ u16 variant;
+ u16 bottom;
+ u16 top;
+} __attribute__ ((packed));
+
+
+struct hfa384x_build_id
+{
+ u16 pri_seq;
+ u16 sec_seq;
+} __attribute__ ((packed));
+
+/* FD01 - Download Buffer */
+struct hfa384x_rid_download_buffer
+{
+ u16 page;
+ u16 offset;
+ u16 length;
+} __attribute__ ((packed));
+
+/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
+struct hfa384x_comms_quality {
+ u16 comm_qual; /* 0 .. 92 */
+ u16 signal_level; /* 27 .. 154 */
+ u16 noise_level; /* 27 .. 154 */
+} __attribute__ ((packed));
+
+
+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
+
+/* New wireless extensions API - SET/GET convention (even ioctl numbers are
+ * root only)
+ */
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
+
+/* following are not in SIOCGIWPRIV list; check permission in the driver code
+ */
+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+};
+
+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
+ HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
+
+
+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
+ AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
+ AP_MAC_CMD_KICKALL = 4 };
+
+
+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
+enum {
+ PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
+ /* Note! Old versions of prism2_srec have a fatal error in CRC-16
+ * calculation, which will corrupt all non-volatile downloads.
+ * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
+ * prevent use of old versions of prism2_srec for non-volatile
+ * download. */
+ PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
+ /* Persistent versions of volatile download commands (keep firmware
+ * data in memory and automatically re-download after hw_reset */
+ PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
+ PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
+};
+
+struct prism2_download_param {
+ u32 dl_cmd;
+ u32 start_addr;
+ u32 num_areas;
+ struct prism2_download_area {
+ u32 addr; /* wlan card address */
+ u32 len;
+ caddr_t ptr; /* pointer to data in user space */
+ } data[0];
+};
+
+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
+#define PRISM2_MAX_DOWNLOAD_LEN 262144
+
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+
+#endif /* HOSTAP_COMMON_H */
diff --git a/contrib/hostapd/hostapd.accept b/contrib/hostapd/hostapd.accept
new file mode 100644
index 000000000000..57122b663449
--- /dev/null
+++ b/contrib/hostapd/hostapd.accept
@@ -0,0 +1,5 @@
+# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
+# with the AP.
+00:11:22:33:44:55
+00:66:77:88:99:aa
+00:00:22:33:44:55
diff --git a/contrib/hostapd/hostapd.c b/contrib/hostapd/hostapd.c
new file mode 100644
index 000000000000..88196417a3be
--- /dev/null
+++ b/contrib/hostapd/hostapd.c
@@ -0,0 +1,802 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "eloop.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "ieee802_11.h"
+#include "accounting.h"
+#include "eapol_sm.h"
+#include "iapp.h"
+#include "ap.h"
+#include "ieee802_11_auth.h"
+#include "sta_info.h"
+#include "driver.h"
+#include "radius_client.h"
+#include "radius_server.h"
+#include "wpa.h"
+#include "ctrl_iface.h"
+#include "tls.h"
+#include "eap_sim_db.h"
+#include "version.h"
+
+
+struct hapd_interfaces {
+ int count;
+ hostapd **hapd;
+};
+
+unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+
+void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
+ char *fmt, ...)
+{
+ char *format, *module_str;
+ int maxlen;
+ va_list ap;
+ int conf_syslog_level, conf_stdout_level;
+ unsigned int conf_syslog, conf_stdout;
+
+ maxlen = strlen(fmt) + 100;
+ format = malloc(maxlen);
+ if (!format)
+ return;
+
+ va_start(ap, fmt);
+
+ 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;
+ default:
+ module_str = NULL;
+ break;
+ }
+
+ if (hapd && hapd->conf && addr)
+ snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
+ hapd->conf->iface, MAC2STR(addr),
+ module_str ? " " : "", module_str, fmt);
+ else if (hapd && hapd->conf)
+ snprintf(format, maxlen, "%s:%s%s %s",
+ hapd->conf->iface, module_str ? " " : "",
+ module_str, fmt);
+ else if (addr)
+ snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
+ MAC2STR(addr), module_str ? " " : "",
+ module_str, fmt);
+ else
+ snprintf(format, maxlen, "%s%s%s",
+ module_str, module_str ? ": " : "", fmt);
+
+ if ((conf_stdout & module) && level >= conf_stdout_level) {
+ vprintf(format, ap);
+ printf("\n");
+ }
+
+ 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;
+ }
+ vsyslog(priority, format, ap);
+ }
+
+ free(format);
+
+ va_end(ap);
+}
+
+
+static void hostapd_deauth_all_stas(hostapd *hapd)
+{
+#if 0
+ u8 addr[ETH_ALEN];
+
+ memset(addr, 0xff, ETH_ALEN);
+ hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+#else
+ /* New Prism2.5/3 STA firmware versions seem to have issues with this
+ * broadcast deauth frame. This gets the firmware in odd state where
+ * nothing works correctly, so let's skip sending this for a while
+ * until the issue has been resolved. */
+#endif
+}
+
+
+/* This function will be called whenever a station associates with the AP */
+void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta)
+{
+ /* IEEE 802.11F (IAPP) */
+ if (hapd->conf->ieee802_11f)
+ iapp_new_station(hapd->iapp, sta);
+
+ /* Start accounting here, if IEEE 802.1X is not used. IEEE 802.1X code
+ * will start accounting after the station has been authorized. */
+ if (!hapd->conf->ieee802_1x)
+ accounting_sta_start(hapd, sta);
+
+ /* Start IEEE 802.1x authentication process for new stations */
+ ieee802_1x_new_station(hapd, sta);
+ wpa_new_station(hapd, sta);
+}
+
+
+static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
+{
+ printf("Signal %d received - terminating\n", sig);
+ eloop_terminate();
+}
+
+
+static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx)
+{
+ struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
+ struct hostapd_config *newconf;
+ int i;
+
+ printf("Signal %d received - reloading configuration\n", sig);
+
+ for (i = 0; i < hapds->count; i++) {
+ hostapd *hapd = hapds->hapd[i];
+ newconf = hostapd_config_read(hapd->config_fname);
+ if (newconf == NULL) {
+ printf("Failed to read new configuration file - "
+ "continuing with old.\n");
+ continue;
+ }
+ /* TODO: update dynamic data based on changed configuration
+ * items (e.g., open/close sockets, remove stations added to
+ * deny list, etc.) */
+ radius_client_flush(hapd->radius);
+ hostapd_config_free(hapd->conf);
+ hapd->conf = newconf;
+ }
+}
+
+
+#ifdef HOSTAPD_DUMP_STATE
+static void hostapd_dump_state(hostapd *hapd)
+{
+ FILE *f;
+ time_t now;
+ struct sta_info *sta;
+ int i;
+ char *buf;
+
+ if (!hapd->conf->dump_log_name) {
+ printf("Dump file not defined - ignoring dump request\n");
+ return;
+ }
+
+ printf("Dumping hostapd state to '%s'\n", hapd->conf->dump_log_name);
+ f = fopen(hapd->conf->dump_log_name, "w");
+ if (f == NULL) {
+ printf("Could not open dump file '%s' for writing.\n",
+ hapd->conf->dump_log_name);
+ return;
+ }
+
+ time(&now);
+ fprintf(f, "hostapd state dump - %s", ctime(&now));
+
+ 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\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]" : ""),
+ (sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" :
+ ""),
+ sta->capability,
+ sta->listen_interval);
+
+ fprintf(f, " supported_rates=");
+ for (i = 0; i < sizeof(sta->supported_rates); i++)
+ if (sta->supported_rates[i] != 0)
+ fprintf(f, "%02x ", sta->supported_rates[i]);
+ fprintf(f, "%s%s%s%s\n",
+ (sta->tx_supp_rates & WLAN_RATE_1M ? "[1M]" : ""),
+ (sta->tx_supp_rates & WLAN_RATE_2M ? "[2M]" : ""),
+ (sta->tx_supp_rates & WLAN_RATE_5M5 ? "[5.5M]" : ""),
+ (sta->tx_supp_rates & WLAN_RATE_11M ? "[11M]" : ""));
+
+ 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);
+ }
+
+ buf = 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);
+
+ 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);
+ free(buf);
+ }
+ fclose(f);
+}
+#endif /* HOSTAPD_DUMP_STATE */
+
+
+static void handle_dump_state(int sig, void *eloop_ctx, void *signal_ctx)
+{
+#ifdef HOSTAPD_DUMP_STATE
+ struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
+ int i;
+
+ for (i = 0; i < hapds->count; i++) {
+ hostapd *hapd = hapds->hapd[i];
+ hostapd_dump_state(hapd);
+ }
+#endif /* HOSTAPD_DUMP_STATE */
+}
+
+
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+ hostapd_ctrl_iface_deinit(hapd);
+
+ free(hapd->default_wep_key);
+ hapd->default_wep_key = NULL;
+ iapp_deinit(hapd->iapp);
+ accounting_deinit(hapd);
+ wpa_deinit(hapd);
+ ieee802_1x_deinit(hapd);
+ hostapd_acl_deinit(hapd);
+ radius_client_deinit(hapd->radius);
+ hapd->radius = NULL;
+ radius_server_deinit(hapd->radius_srv);
+ hapd->radius_srv = NULL;
+
+ hostapd_wireless_event_deinit(hapd);
+
+ if (hapd->driver)
+ hostapd_driver_deinit(hapd);
+
+ hostapd_config_free(hapd->conf);
+ hapd->conf = NULL;
+
+ free(hapd->config_fname);
+
+#ifdef EAP_TLS_FUNCS
+ if (hapd->ssl_ctx) {
+ tls_deinit(hapd->ssl_ctx);
+ hapd->ssl_ctx = NULL;
+ }
+#endif /* EAP_TLS_FUNCS */
+
+ if (hapd->eap_sim_db_priv)
+ eap_sim_db_deinit(hapd->eap_sim_db_priv);
+}
+
+
+static int hostapd_flush_old_stations(hostapd *hapd)
+{
+ int ret = 0;
+
+ printf("Flushing old station entries\n");
+ if (hostapd_flush(hapd)) {
+ printf("Could not connect to kernel driver.\n");
+ ret = -1;
+ }
+ printf("Deauthenticate all stations\n");
+ hostapd_deauth_all_stas(hapd);
+
+ return ret;
+}
+
+
+static int hostapd_setup_interface(struct hostapd_data *hapd)
+{
+ struct hostapd_config *conf = hapd->conf;
+ u8 ssid[HOSTAPD_SSID_LEN + 1];
+ int ssid_len, set_ssid;
+ int ret = 0;
+
+ if (hostapd_driver_init(hapd)) {
+ printf("%s driver initialization failed.\n",
+ hapd->driver ? hapd->driver->name : "Unknown");
+ hapd->driver = NULL;
+ 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) {
+ printf("Could not read SSID from system\n");
+ return -1;
+ }
+ if (conf->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_len != ssid_len ||
+ memcmp(conf->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_len = ssid_len;
+ memcpy(conf->ssid, ssid, conf->ssid_len);
+ conf->ssid[conf->ssid_len] = '\0';
+ }
+
+ printf("Using interface %s with hwaddr " MACSTR " and ssid '%s'\n",
+ hapd->conf->iface, MAC2STR(hapd->own_addr), hapd->conf->ssid);
+
+ if (hostapd_setup_wpa_psk(conf)) {
+ printf("WPA-PSK setup failed.\n");
+ 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,
+ conf->ssid_len)) {
+ printf("Could not set SSID for kernel driver\n");
+ return -1;
+ }
+
+ hapd->radius = radius_client_init(hapd);
+ if (hapd->radius == NULL) {
+ printf("RADIUS client initialization failed.\n");
+ return -1;
+ }
+ if (conf->radius_server_clients) {
+ struct radius_server_conf srv;
+ memset(&srv, 0, sizeof(srv));
+ srv.client_file = conf->radius_server_clients;
+ srv.auth_port = conf->radius_server_auth_port;
+ srv.hostapd_conf = conf;
+ srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
+ srv.ssl_ctx = hapd->ssl_ctx;
+ hapd->radius_srv = radius_server_init(&srv);
+ if (hapd->radius_srv == NULL) {
+ printf("RADIUS server initialization failed.\n");
+ return -1;
+ }
+ }
+ if (hostapd_acl_init(hapd)) {
+ printf("ACL initialization failed.\n");
+ return -1;
+ }
+ if (ieee802_1x_init(hapd)) {
+ printf("IEEE 802.1X initialization failed.\n");
+ return -1;
+ }
+
+ if (hapd->conf->wpa && wpa_init(hapd)) {
+ printf("WPA initialization failed.\n");
+ return -1;
+ }
+
+ if (accounting_init(hapd)) {
+ printf("Accounting initialization failed.\n");
+ return -1;
+ }
+
+ if (hapd->conf->ieee802_11f &&
+ (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+ printf("IEEE 802.11F (IAPP) initialization failed.\n");
+ return -1;
+ }
+
+ if (hostapd_wireless_event_init(hapd) < 0)
+ return -1;
+
+ if (hostapd_flush_old_stations(hapd))
+ return -1;
+
+ if (hostapd_ctrl_iface_init(hapd)) {
+ printf("Failed to setup control interface\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+struct driver {
+ struct driver *next;
+ char *name;
+ const struct driver_ops *ops;
+};
+static struct driver *drivers = NULL;
+
+void driver_register(const char *name, const struct driver_ops *ops)
+{
+ struct driver *d;
+
+ d = malloc(sizeof(struct driver));
+ if (d == NULL) {
+ printf("Failed to register driver %s!\n", name);
+ return;
+ }
+ d->name = strdup(name);
+ if (d->name == NULL) {
+ printf("Failed to register driver %s!\n", name);
+ free(d);
+ return;
+ }
+ d->ops = ops;
+
+ d->next = drivers;
+ drivers = d;
+}
+
+
+void driver_unregister(const char *name)
+{
+ struct driver *p, **pp;
+
+ for (pp = &drivers; (p = *pp) != NULL; pp = &p->next) {
+ if (strcasecmp(p->name, name) == 0) {
+ *pp = p->next;
+ p->next = NULL;
+ free(p->name);
+ free(p);
+ break;
+ }
+ }
+}
+
+
+static void driver_unregister_all(void)
+{
+ struct driver *p, *pp;
+ p = drivers;
+ drivers = NULL;
+ while (p) {
+ pp = p;
+ p = p->next;
+ free(pp->name);
+ free(pp);
+ }
+}
+
+
+const struct driver_ops * driver_lookup(const char *name)
+{
+ struct driver *p;
+
+ if (strcmp(name, "default") == 0) {
+ p = drivers;
+ while (p && p->next)
+ p = p->next;
+ return p->ops;
+ }
+
+ for (p = drivers; p != NULL; p = p->next) {
+ if (strcasecmp(p->name, name) == 0)
+ return p->ops;
+ }
+
+ return NULL;
+}
+
+
+static void show_version(void)
+{
+ fprintf(stderr,
+ "hostapd v" VERSION_STR "\n"
+ "Host AP user space daemon for management functionality of "
+ "Host AP kernel driver\n"
+ "Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> "
+ "and contributors\n");
+}
+
+
+static void usage(void)
+{
+ show_version();
+ fprintf(stderr,
+ "\n"
+ "usage: hostapd [-hdB] <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"
+ " -K include key data in debug messages\n"
+ " -t include timestamps in some debug messages\n"
+ " -v show hostapd version\n");
+
+ exit(1);
+}
+
+
+static hostapd * hostapd_init(const char *config_file)
+{
+ hostapd *hapd;
+
+ hapd = malloc(sizeof(*hapd));
+ if (hapd == NULL) {
+ printf("Could not allocate memory for hostapd data\n");
+ goto fail;
+ }
+ memset(hapd, 0, sizeof(*hapd));
+
+ hapd->config_fname = strdup(config_file);
+ if (hapd->config_fname == NULL) {
+ printf("Could not allocate memory for config_fname\n");
+ goto fail;
+ }
+
+ hapd->conf = hostapd_config_read(hapd->config_fname);
+ if (hapd->conf == NULL) {
+ goto fail;
+ }
+
+ if (hapd->conf->individual_wep_key_len > 0) {
+ /* use key0 in individual key and key1 in broadcast key */
+ hapd->default_wep_key_idx = 1;
+ }
+
+#ifdef EAP_TLS_FUNCS
+ if (hapd->conf->eap_authenticator &&
+ (hapd->conf->ca_cert || hapd->conf->server_cert)) {
+ hapd->ssl_ctx = tls_init();
+ if (hapd->ssl_ctx == NULL) {
+ printf("Failed to initialize TLS\n");
+ goto fail;
+ }
+ if (tls_global_ca_cert(hapd->ssl_ctx, hapd->conf->ca_cert)) {
+ printf("Failed to load CA certificate (%s)\n",
+ hapd->conf->ca_cert);
+ goto fail;
+ }
+ if (tls_global_client_cert(hapd->ssl_ctx,
+ hapd->conf->server_cert)) {
+ printf("Failed to load server certificate (%s)\n",
+ hapd->conf->server_cert);
+ goto fail;
+ }
+ if (tls_global_private_key(hapd->ssl_ctx,
+ hapd->conf->private_key,
+ hapd->conf->private_key_passwd)) {
+ printf("Failed to load private key (%s)\n",
+ hapd->conf->private_key);
+ }
+ }
+#endif /* EAP_TLS_FUNCS */
+
+ if (hapd->conf->eap_sim_db) {
+ hapd->eap_sim_db_priv =
+ eap_sim_db_init(hapd->conf->eap_sim_db);
+ if (hapd->eap_sim_db_priv == NULL) {
+ printf("Failed to initialize EAP-SIM database "
+ "interface\n");
+ goto fail;
+ }
+ }
+
+ if (hapd->conf->assoc_ap)
+ hapd->assoc_ap_state = WAIT_BEACON;
+
+ /* FIX: need to fix this const vs. not */
+ hapd->driver = (struct driver_ops *) hapd->conf->driver;
+
+ return hapd;
+
+fail:
+ if (hapd) {
+ if (hapd->ssl_ctx)
+ tls_deinit(hapd->ssl_ctx);
+ if (hapd->conf)
+ hostapd_config_free(hapd->conf);
+ free(hapd->config_fname);
+ free(hapd);
+ }
+ return NULL;
+}
+
+
+void register_drivers(void);
+
+int main(int argc, char *argv[])
+{
+ struct hapd_interfaces interfaces;
+ int ret = 1, i, j;
+ int c, debug = 0, daemonize = 0;
+
+ for (;;) {
+ c = getopt(argc, argv, "BdhKtv");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'h':
+ usage();
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'B':
+ daemonize++;
+ break;
+ case 'K':
+ wpa_debug_show_keys++;
+ break;
+ case 't':
+ wpa_debug_timestamp++;
+ break;
+ case 'v':
+ show_version();
+ exit(1);
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind == argc)
+ usage();
+
+ register_drivers(); /* NB: generated by Makefile */
+
+ interfaces.count = argc - optind;
+
+ interfaces.hapd = malloc(interfaces.count * sizeof(hostapd *));
+ if (interfaces.hapd == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+
+ eloop_init(&interfaces);
+ eloop_register_signal(SIGHUP, handle_reload, NULL);
+ eloop_register_signal(SIGINT, handle_term, NULL);
+ eloop_register_signal(SIGTERM, handle_term, NULL);
+ eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
+
+ for (i = 0; i < interfaces.count; i++) {
+ printf("Configuration file: %s\n", argv[optind + i]);
+ interfaces.hapd[i] = hostapd_init(argv[optind + i]);
+ if (!interfaces.hapd[i])
+ goto out;
+ for (j = 0; j < debug; j++) {
+ if (interfaces.hapd[i]->conf->logger_stdout_level > 0)
+ interfaces.hapd[i]->conf->
+ logger_stdout_level--;
+ interfaces.hapd[i]->conf->debug++;
+ }
+ if (hostapd_setup_interface(interfaces.hapd[i]))
+ goto out;
+ wpa_debug_level -= interfaces.hapd[0]->conf->debug;
+ }
+
+ if (daemonize && daemon(0, 0)) {
+ perror("daemon");
+ goto out;
+ }
+
+ openlog("hostapd", 0, LOG_DAEMON);
+
+ eloop_run();
+
+ for (i = 0; i < interfaces.count; i++) {
+ hostapd_free_stas(interfaces.hapd[i]);
+ hostapd_flush_old_stations(interfaces.hapd[i]);
+ }
+
+ ret = 0;
+
+ out:
+ for (i = 0; i < interfaces.count; i++) {
+ if (!interfaces.hapd[i])
+ continue;
+
+ hostapd_cleanup(interfaces.hapd[i]);
+ free(interfaces.hapd[i]);
+ }
+ free(interfaces.hapd);
+
+ eloop_destroy();
+
+ closelog();
+
+ driver_unregister_all();
+
+ return ret;
+}
diff --git a/contrib/hostapd/hostapd.conf b/contrib/hostapd/hostapd.conf
new file mode 100644
index 000000000000..bb792dc26009
--- /dev/null
+++ b/contrib/hostapd/hostapd.conf
@@ -0,0 +1,293 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' prefix, i.e., wlan0 uses wlan0ap for
+# management frames)
+interface=wlan0
+
+# Driver interface type (hostap/wired/madwifi/prism54; default: hostap)
+# driver=hostap
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 5 (32) = IAPP
+#
+# Levels (minimum value for logged events):
+# 0 = verbose debugging
+# 1 = debugging
+# 2 = informational messages
+# 3 = notification
+# 4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Debugging: 0 = no, 1 = minimal, 2 = verbose, 3 = msg dumps, 4 = excessive
+debug=0
+
+# Dump file for state information (on SIGUSR1)
+dump_file=/tmp/hostapd.dump
+
+# Interface for separate control program. If this is specified, wpa_supplicant
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run wpa_supplicant as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
+# want to allow non-root users to use the contron interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+ssid=test
+
+# Station MAC address -based authentication
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=3
+
+# Associate as a station to another AP while still acting as an AP on the same
+# channel.
+#assoc_ap_addr=00:12:34:56:78:9a
+
+
+##### IEEE 802.1X (and IEEE 802.1aa/D4) related configuration #################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# Use integrated EAP authenticator instead of external RADIUS authentication
+# server
+eap_authenticator=0
+
+# Path for EAP authenticator user database
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the file name for the GSM
+# authentication triplets.
+#eap_sim_db=/etc/hostapd.sim_db
+
+# Optional displayable message sent with EAP Request-Identity
+eap_message=hello
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+#eap_reauth_period=3600
+
+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
+
+# Interface to be used for IAPP broadcast packets
+#iapp_interface=eth0
+
+
+##### RADIUS configuration ####################################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+#nas_identifier=ap.example.com
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP authenticator is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+# (dot11RSNAConfigAuthenticationSuitesTable)
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+# (dot11RSNAConfigPairwiseCiphersTable)
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+#wpa_group_rekey=600
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
diff --git a/contrib/hostapd/hostapd.deny b/contrib/hostapd/hostapd.deny
new file mode 100644
index 000000000000..1616678f579e
--- /dev/null
+++ b/contrib/hostapd/hostapd.deny
@@ -0,0 +1,5 @@
+# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
+# with the AP.
+00:20:30:40:50:60
+00:ab:cd:ef:12:34
+00:00:30:40:50:60
diff --git a/contrib/hostapd/hostapd.eap_user b/contrib/hostapd/hostapd.eap_user
new file mode 100644
index 000000000000..529334a0e157
--- /dev/null
+++ b/contrib/hostapd/hostapd.eap_user
@@ -0,0 +1,45 @@
+# hostapd user database for integrated EAP authenticator
+# Each line must contain an identity, EAP method(s), and an optional password
+# separated with whitespace (space or tab). The identity and password must be
+# double quoted ("user"). [2] flag in the end of the line can be used to mark
+# users for tunneled phase 2 authentication (e.g., within EAP-PEAP). In these
+# cases, an anonymous identity can be used in the unencrypted phase 1 and the
+# real user identity is transmitted only within the encrypted tunnel in phase
+# 2. If non-anonymous access is needed, two user entries is needed, one for
+# phase 1 and another with the same username for phase 2.
+#
+# EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-SIM do not use password option.
+# EAP-MD5, EAP-MSCHAPV2, and EAP-GTC require a password.
+# EAP-PEAP and EAP-TTLS require Phase 2 configuration.
+#
+# * can be used as a wildcard to match any user identity. The main purposes for
+# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
+# avoid having to configure every certificate for EAP-TLS authentication. The
+# first matching entry is selected, so * should be used as the last phase 1
+# user entry.
+#
+# Multiple methods can be configured to make the authenticator try them one by
+# one until the peer accepts one. The method names are separated with a
+# comma (,).
+#
+# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
+# version based on the Phase 1 identity. Without this flag, the EAP
+# authenticator advertises the highest supported version and select the version
+# based on the first PEAP packet from the supplicant.
+
+# Phase 1 users
+"user" MD5 "password"
+"test user" MD5 "secret"
+"example user" TLS
+"DOMAIN\user" MSCHAPV2 "password"
+"gtc user" GTC "password"
+"ttls" TTLS
+"not anonymous" PEAP
+* PEAP,TTLS,TLS,SIM
+
+# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
+"t-md5" MD5 "password" [2]
+"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2]
+"t-gtc" GTC "password" [2]
+"not anonymous" MSCHAPV2 "password" [2]
+"user" MD5,GTC,MSCHAPV2 "password" [2]
diff --git a/contrib/hostapd/hostapd.h b/contrib/hostapd/hostapd.h
new file mode 100644
index 000000000000..9e6da65b6cdc
--- /dev/null
+++ b/contrib/hostapd/hostapd.h
@@ -0,0 +1,134 @@
+#ifndef HOSTAPD_H
+#define HOSTAPD_H
+
+#include "common.h"
+#include "ap.h"
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#endif
+
+#include "hostap_common.h"
+#include "config.h"
+
+struct ieee8023_hdr {
+ u8 dest[6];
+ u8 src[6];
+ u16 ethertype;
+} __attribute__ ((packed));
+
+
+struct ieee80211_hdr {
+ u16 frame_control;
+ u16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ u16 seq_ctrl;
+ /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
+ */
+} __attribute__ ((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))
+
+/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
+ * frames that might be longer than normal default MTU and they are not
+ * fragmented */
+#define HOSTAPD_MTU 2290
+
+extern unsigned char rfc1042_header[6];
+
+typedef struct hostapd_data hostapd;
+
+struct hostap_sta_driver_data {
+ unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+};
+
+struct driver_ops;
+struct wpa_ctrl_dst;
+struct radius_server_data;
+
+struct hostapd_data {
+ struct hostapd_config *conf;
+ char *config_fname;
+
+ u8 own_addr[6];
+
+ int num_sta; /* number of entries in sta_list */
+ struct sta_info *sta_list; /* STA info list head */
+ struct sta_info *sta_hash[STA_HASH_SIZE];
+
+ /* pointers to STA info; based on allocated AID or NULL if AID free
+ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+ * and so on
+ */
+ struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
+
+ struct driver_ops *driver;
+
+ u8 *default_wep_key;
+ u8 default_wep_key_idx;
+
+ struct radius_client_data *radius;
+ u32 acct_session_id_hi, acct_session_id_lo;
+
+ struct iapp_data *iapp;
+
+ enum { DO_NOT_ASSOC = 0, WAIT_BEACON, AUTHENTICATE, ASSOCIATE,
+ ASSOCIATED } assoc_ap_state;
+ char assoc_ap_ssid[33];
+ int assoc_ap_ssid_len;
+ u16 assoc_ap_aid;
+
+ struct hostapd_cached_radius_acl *acl_cache;
+ struct hostapd_acl_query_data *acl_queries;
+
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+ struct wpa_authenticator *wpa_auth;
+
+#define PMKID_HASH_SIZE 128
+#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
+ struct rsn_pmksa_cache *pmkid[PMKID_HASH_SIZE];
+ struct rsn_pmksa_cache *pmksa;
+ int pmksa_count;
+
+ 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;
+};
+
+void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta);
+void hostapd_logger(hostapd *hapd, u8 *addr, unsigned int module, int level,
+ char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
+
+
+#define HOSTAPD_DEBUG(level, args...) \
+do { \
+ if (hapd->conf == NULL || hapd->conf->debug >= (level)) \
+ printf(args); \
+} while (0)
+
+#define HOSTAPD_DEBUG_COND(level) (hapd->conf->debug >= (level))
+
+#endif /* HOSTAPD_H */
diff --git a/contrib/hostapd/hostapd.radius_clients b/contrib/hostapd/hostapd.radius_clients
new file mode 100644
index 000000000000..3980427253b4
--- /dev/null
+++ b/contrib/hostapd/hostapd.radius_clients
@@ -0,0 +1,4 @@
+# RADIUS client configuration for the RADIUS server
+10.1.2.3 secret passphrase
+192.168.1.0/24 another very secret passphrase
+0.0.0.0/0 radius
diff --git a/contrib/hostapd/hostapd.sim_db b/contrib/hostapd/hostapd.sim_db
new file mode 100644
index 000000000000..01c593de8d2d
--- /dev/null
+++ b/contrib/hostapd/hostapd.sim_db
@@ -0,0 +1,9 @@
+# Example GSM authentication triplet file for EAP-SIM authenticator
+# IMSI:Kc:SRES:RAND
+# IMSI: ASCII string (numbers)
+# Kc: hex, 8 octets
+# SRES: hex, 4 octets
+# RAND: hex, 16 octets
+234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
diff --git a/contrib/hostapd/hostapd.wpa_psk b/contrib/hostapd/hostapd.wpa_psk
new file mode 100644
index 000000000000..0a9499acd736
--- /dev/null
+++ b/contrib/hostapd/hostapd.wpa_psk
@@ -0,0 +1,9 @@
+# List of WPA PSKs. Each line, except for empty lines and lines starting
+# with #, must contain a MAC address and PSK separated with a space.
+# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
+# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
+# characters or as a 256-bit hex PSK (64 hex digits).
+00:00:00:00:00:00 secret passphrase
+00:11:22:33:44:55 another passphrase
+00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+00:00:00:00:00:00 another passphrase for all STAs
diff --git a/contrib/hostapd/hostapd_cli.c b/contrib/hostapd/hostapd_cli.c
new file mode 100644
index 000000000000..5e305dcee988
--- /dev/null
+++ b/contrib/hostapd/hostapd_cli.c
@@ -0,0 +1,600 @@
+/*
+ * hostapd - command line interface for hostapd daemon
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "hostapd_ctrl.h"
+#include "version.h"
+
+
+static const char *hostapd_cli_version =
+"hostapd_cli v" VERSION_STR "\n"
+"Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
+
+
+static const char *hostapd_cli_license =
+"This program is free software. You can distribute it and/or modify it\n"
+"under the terms of the GNU General Public License version 2.\n"
+"\n"
+"Alternatively, this software may be distributed under the terms of the\n"
+"BSD license. See README and COPYING for more details.\n";
+
+static const char *hostapd_cli_full_license =
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License version 2 as\n"
+"published by the Free Software Foundation.\n"
+"\n"
+"This program is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n"
+"\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this program; if not, write to the Free Software\n"
+"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
+"\n"
+"Alternatively, this software may be distributed under the terms of the\n"
+"BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+" notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+" notice, this list of conditions and the following disclaimer in the\n"
+" documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+" names of its contributors may be used to endorse or promote products\n"
+" derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+static const char *commands_help =
+"commands:\n"
+" mib = get MIB variables (dot1x, dot11, radius)\n"
+" sta <addr> = get MIB vatiables for one station\n"
+" all_sta = get MIB variables for all stations\n"
+" help = show this usage help\n"
+" interface [ifname] = show interfaces/select interface\n"
+" level <debug level> = change debug level\n"
+" license = show full hostapd_cli license\n"
+" quit = exit hostapd_cli\n";
+
+static struct hostapd_ctrl *ctrl_conn;
+static int hostapd_cli_quit = 0;
+static int hostapd_cli_attached = 0;
+static const char *ctrl_iface_dir = "/var/run/hostapd";
+static char *ctrl_ifname = NULL;
+
+
+static void usage(void)
+{
+ printf("hostapd_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
+ "[command..]\n"
+ " -h = help (show this usage text)\n"
+ " -v = shown version information\n"
+ " default path: /var/run/hostapd\n"
+ " default interface: first interface found in socket path\n"
+ "%s",
+ commands_help);
+}
+
+
+static struct hostapd_ctrl * hostapd_cli_open_connection(const char *ifname)
+{
+ char *cfile;
+ int flen;
+
+ if (ifname == NULL)
+ return NULL;
+
+ flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
+ cfile = malloc(flen);
+ if (cfile == NULL)
+ return NULL;
+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
+
+ ctrl_conn = hostapd_ctrl_open(cfile);
+ free(cfile);
+ return ctrl_conn;
+}
+
+
+static void hostapd_cli_close_connection(void)
+{
+ if (ctrl_conn == NULL)
+ return;
+
+ if (hostapd_cli_attached) {
+ hostapd_ctrl_detach(ctrl_conn);
+ hostapd_cli_attached = 0;
+ }
+ hostapd_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+}
+
+
+static void hostapd_cli_msg_cb(char *msg, size_t len)
+{
+ printf("%s\n", msg);
+}
+
+
+static int _hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd,
+ int print)
+{
+ char buf[4096];
+ size_t len;
+ int ret;
+
+ if (ctrl_conn == NULL) {
+ printf("Not connected to hostapd - command dropped.\n");
+ return -1;
+ }
+ len = sizeof(buf) - 1;
+ ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ hostapd_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+ if (print) {
+ buf[len] = '\0';
+ printf("%s", buf);
+ }
+ return 0;
+}
+
+
+static inline int hostapd_ctrl_command(struct hostapd_ctrl *ctrl, char *cmd)
+{
+ return _hostapd_ctrl_command(ctrl, cmd, 1);
+}
+
+
+static int hostapd_cli_cmd_ping(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_ctrl_command(ctrl, "PING");
+}
+
+
+static int hostapd_cli_cmd_mib(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_ctrl_command(ctrl, "MIB");
+}
+
+
+static int hostapd_cli_cmd_sta(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+ if (argc != 1) {
+ printf("Invalid 'sta' command - exactly one argument, STA "
+ "address, is required.\n");
+ return -1;
+ }
+ snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+ return hostapd_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_ctrl_command_sta(struct hostapd_ctrl *ctrl, char *cmd,
+ char *addr, size_t addr_len)
+{
+ char buf[4096], *pos;
+ size_t len;
+ int ret;
+
+ if (ctrl_conn == NULL) {
+ printf("Not connected to hostapd - command dropped.\n");
+ return -1;
+ }
+ len = sizeof(buf) - 1;
+ ret = hostapd_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ hostapd_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ if (memcmp(buf, "FAIL", 4) == 0)
+ return -1;
+ printf("%s", buf);
+
+ pos = buf;
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ *pos = '\0';
+ snprintf(addr, addr_len, "%s", buf);
+ return 0;
+}
+
+
+static int hostapd_cli_cmd_all_sta(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char addr[32], cmd[64];
+
+ if (hostapd_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+ return 0;
+ do {
+ snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (hostapd_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+ return -1;
+}
+
+
+static int hostapd_cli_cmd_help(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ printf("%s", commands_help);
+ return 0;
+}
+
+
+static int hostapd_cli_cmd_license(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+ return 0;
+}
+
+
+static int hostapd_cli_cmd_quit(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ hostapd_cli_quit = 1;
+ return 0;
+}
+
+
+static int hostapd_cli_cmd_level(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ if (argc != 1) {
+ printf("Invalid LEVEL command: needs one argument (debug "
+ "level)\n");
+ return 0;
+ }
+ snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+ return hostapd_ctrl_command(ctrl, cmd);
+}
+
+
+static void hostapd_cli_list_interfaces(struct hostapd_ctrl *ctrl)
+{
+ struct dirent *dent;
+ DIR *dir;
+
+ dir = opendir(ctrl_iface_dir);
+ if (dir == NULL) {
+ printf("Control interface directory '%s' could not be "
+ "openned.\n", ctrl_iface_dir);
+ return;
+ }
+
+ printf("Available interfaces:\n");
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("%s\n", dent->d_name);
+ }
+ closedir(dir);
+}
+
+
+static int hostapd_cli_cmd_interface(struct hostapd_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 1) {
+ hostapd_cli_list_interfaces(ctrl);
+ return 0;
+ }
+
+ hostapd_cli_close_connection();
+ free(ctrl_ifname);
+ ctrl_ifname = strdup(argv[0]);
+
+ if (hostapd_cli_open_connection(ctrl_ifname)) {
+ printf("Connected to interface '%s.\n", ctrl_ifname);
+ if (hostapd_ctrl_attach(ctrl_conn) == 0) {
+ hostapd_cli_attached = 1;
+ } else {
+ printf("Warning: Failed to attach to "
+ "hostapd.\n");
+ }
+ } else {
+ printf("Could not connect to interface '%s' - re-trying\n",
+ ctrl_ifname);
+ }
+ return 0;
+}
+
+
+struct hostapd_cli_cmd {
+ const char *cmd;
+ int (*handler)(struct hostapd_ctrl *ctrl, int argc, char *argv[]);
+};
+
+static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ { "ping", hostapd_cli_cmd_ping },
+ { "mib", hostapd_cli_cmd_mib },
+ { "sta", hostapd_cli_cmd_sta },
+ { "all_sta", hostapd_cli_cmd_all_sta },
+ { "help", hostapd_cli_cmd_help },
+ { "interface", hostapd_cli_cmd_interface },
+ { "level", hostapd_cli_cmd_level },
+ { "license", hostapd_cli_cmd_license },
+ { "quit", hostapd_cli_cmd_quit },
+ { NULL, NULL }
+};
+
+
+static void wpa_request(struct hostapd_ctrl *ctrl, int argc, char *argv[])
+{
+ struct hostapd_cli_cmd *cmd, *match = NULL;
+ int count;
+
+ count = 0;
+ cmd = hostapd_cli_commands;
+ while (cmd->cmd) {
+ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
+ match = cmd;
+ count++;
+ }
+ cmd++;
+ }
+
+ if (count > 1) {
+ printf("Ambiguous command '%s'; possible commands:", argv[0]);
+ cmd = hostapd_cli_commands;
+ while (cmd->cmd) {
+ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
+ 0) {
+ printf(" %s", cmd->cmd);
+ }
+ cmd++;
+ }
+ printf("\n");
+ } else if (count == 0) {
+ printf("Unknown command '%s'\n", argv[0]);
+ } else {
+ match->handler(ctrl, argc - 1, &argv[1]);
+ }
+}
+
+
+static void hostapd_cli_recv_pending(struct hostapd_ctrl *ctrl, int in_read)
+{
+ int first = 1;
+ if (ctrl_conn == NULL)
+ return;
+ while (hostapd_ctrl_pending(ctrl)) {
+ char buf[256];
+ size_t len = sizeof(buf) - 1;
+ if (hostapd_ctrl_recv(ctrl, buf, &len) == 0) {
+ buf[len] = '\0';
+ if (in_read && first)
+ printf("\n");
+ first = 0;
+ printf("%s\n", buf);
+ } else {
+ printf("Could not read pending message.\n");
+ break;
+ }
+ }
+}
+
+
+static void hostapd_cli_interactive(void)
+{
+ const int max_args = 10;
+ char cmd[256], *res, *argv[max_args], *pos;
+ int argc;
+
+ printf("\nInteractive mode\n\n");
+
+ do {
+ hostapd_cli_recv_pending(ctrl_conn, 0);
+ printf("> ");
+ alarm(1);
+ res = fgets(cmd, sizeof(cmd), stdin);
+ alarm(0);
+ if (res == NULL)
+ break;
+ pos = cmd;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ argc = 0;
+ pos = cmd;
+ for (;;) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[argc] = pos;
+ argc++;
+ if (argc == max_args)
+ break;
+ while (*pos != '\0' && *pos != ' ')
+ pos++;
+ if (*pos == ' ')
+ *pos++ = '\0';
+ }
+ if (argc)
+ wpa_request(ctrl_conn, argc, argv);
+ } while (!hostapd_cli_quit);
+}
+
+
+static void hostapd_cli_terminate(int sig)
+{
+ hostapd_cli_close_connection();
+ exit(0);
+}
+
+
+static void hostapd_cli_alarm(int sig)
+{
+ if (ctrl_conn && _hostapd_ctrl_command(ctrl_conn, "PING", 0)) {
+ printf("Connection to hostapd lost - trying to reconnect\n");
+ hostapd_cli_close_connection();
+ }
+ if (!ctrl_conn) {
+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ if (ctrl_conn) {
+ printf("Connection to hostapd re-established\n");
+ if (hostapd_ctrl_attach(ctrl_conn) == 0) {
+ hostapd_cli_attached = 1;
+ } else {
+ printf("Warning: Failed to attach to "
+ "hostapd.\n");
+ }
+ }
+ }
+ if (ctrl_conn)
+ hostapd_cli_recv_pending(ctrl_conn, 1);
+ alarm(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int interactive;
+ int warning_displayed = 0;
+ int c;
+
+ for (;;) {
+ c = getopt(argc, argv, "hi:p:v");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'h':
+ usage();
+ return 0;
+ case 'v':
+ printf("%s\n", hostapd_cli_version);
+ return 0;
+ case 'i':
+ ctrl_ifname = strdup(optarg);
+ break;
+ case 'p':
+ ctrl_iface_dir = optarg;
+ break;
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ interactive = argc == optind;
+
+ if (interactive) {
+ printf("%s\n\n%s\n\n", hostapd_cli_version,
+ hostapd_cli_license);
+ }
+
+ for (;;) {
+ if (ctrl_ifname == NULL) {
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ if (dir) {
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n",
+ dent->d_name);
+ ctrl_ifname = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+ }
+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ if (ctrl_conn) {
+ if (warning_displayed)
+ printf("Connection established.\n");
+ break;
+ }
+
+ if (!interactive) {
+ perror("Failed to connect to hostapd - "
+ "hostapd_ctrl_open");
+ return -1;
+ }
+
+ if (!warning_displayed) {
+ printf("Could not connect to hostapd - re-trying\n");
+ warning_displayed = 1;
+ }
+ sleep(1);
+ continue;
+ }
+
+ signal(SIGINT, hostapd_cli_terminate);
+ signal(SIGTERM, hostapd_cli_terminate);
+ signal(SIGALRM, hostapd_cli_alarm);
+
+ if (interactive) {
+ if (hostapd_ctrl_attach(ctrl_conn) == 0) {
+ hostapd_cli_attached = 1;
+ } else {
+ printf("Warning: Failed to attach to hostapd.\n");
+ }
+ hostapd_cli_interactive();
+ } else
+ wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+
+ free(ctrl_ifname);
+ hostapd_cli_close_connection();
+ return 0;
+}
diff --git a/contrib/hostapd/hostapd_ctrl.c b/contrib/hostapd/hostapd_ctrl.c
new file mode 100644
index 000000000000..55b690451b50
--- /dev/null
+++ b/contrib/hostapd/hostapd_ctrl.c
@@ -0,0 +1,188 @@
+/*
+ * hostapd - hostapd control interface library
+ * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include "hostapd_ctrl.h"
+
+
+struct hostapd_ctrl {
+ int s;
+ struct sockaddr_un local;
+ struct sockaddr_un dest;
+};
+
+
+struct hostapd_ctrl * hostapd_ctrl_open(const char *ctrl_path)
+{
+ struct hostapd_ctrl *ctrl;
+ static int counter = 0;
+
+ ctrl = malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ memset(ctrl, 0, sizeof(*ctrl));
+
+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (ctrl->s < 0) {
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->local.sun_family = AF_UNIX;
+ snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+ "/tmp/hostapd_ctrl_%d-%d", getpid(), counter++);
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local.sun_family) +
+ strlen(ctrl->local.sun_path)) < 0) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->dest.sun_family = AF_UNIX;
+ strncpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path));
+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+ sizeof(ctrl->dest.sun_family) +
+ strlen(ctrl->dest.sun_path)) < 0) {
+ close(ctrl->s);
+ unlink(ctrl->local.sun_path);
+ free(ctrl);
+ return NULL;
+ }
+
+ return ctrl;
+}
+
+
+void hostapd_ctrl_close(struct hostapd_ctrl *ctrl)
+{
+ unlink(ctrl->local.sun_path);
+ close(ctrl->s);
+ free(ctrl);
+}
+
+
+int hostapd_ctrl_request(struct hostapd_ctrl *ctrl, char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len))
+{
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+
+ if (send(ctrl->s, cmd, cmd_len, 0) < 0)
+ return -1;
+
+ for (;;) {
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ if (FD_ISSET(ctrl->s, &rfds)) {
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ if (res > 0 && reply[0] == '<') {
+ /* This is an unsolicited message from
+ * wpa_supplicant, not the reply to the
+ * request. Use msg_cb to report this to the
+ * caller. */
+ if (msg_cb) {
+ /* Make sure the message is nul
+ * terminated. */
+ if (res == *reply_len)
+ res = (*reply_len) - 1;
+ reply[res] = '\0';
+ msg_cb(reply, res);
+ }
+ continue;
+ }
+ *reply_len = res;
+ break;
+ } else {
+ return -2;
+ }
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_attach_helper(struct hostapd_ctrl *ctrl, int attach)
+{
+ char buf[10];
+ int ret;
+ size_t len = 10;
+
+ ret = hostapd_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+ buf, &len, NULL);
+ if (ret < 0)
+ return ret;
+ if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
+ return 0;
+ return -1;
+}
+
+
+int hostapd_ctrl_attach(struct hostapd_ctrl *ctrl)
+{
+ return hostapd_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int hostapd_ctrl_detach(struct hostapd_ctrl *ctrl)
+{
+ return hostapd_ctrl_attach_helper(ctrl, 0);
+}
+
+
+int hostapd_ctrl_recv(struct hostapd_ctrl *ctrl, char *reply,
+ size_t *reply_len)
+{
+ int res;
+
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ *reply_len = res;
+ return 0;
+}
+
+
+int hostapd_ctrl_pending(struct hostapd_ctrl *ctrl)
+{
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int hostapd_ctrl_get_fd(struct hostapd_ctrl *ctrl)
+{
+ return ctrl->s;
+}
diff --git a/contrib/hostapd/hostapd_ctrl.h b/contrib/hostapd/hostapd_ctrl.h
new file mode 100644
index 000000000000..7ba221e19fc1
--- /dev/null
+++ b/contrib/hostapd/hostapd_ctrl.h
@@ -0,0 +1,18 @@
+#ifndef HOSTAPD_CTRL_H
+#define HOSTAPD_CTRL_H
+
+struct hostapd_ctrl;
+
+struct hostapd_ctrl * hostapd_ctrl_open(const char *ctrl_path);
+void hostapd_ctrl_close(struct hostapd_ctrl *ctrl);
+int hostapd_ctrl_request(struct hostapd_ctrl *ctrl, char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len));
+int hostapd_ctrl_attach(struct hostapd_ctrl *ctrl);
+int hostapd_ctrl_detach(struct hostapd_ctrl *ctrl);
+int hostapd_ctrl_recv(struct hostapd_ctrl *ctrl, char *reply,
+ size_t *reply_len);
+int hostapd_ctrl_pending(struct hostapd_ctrl *ctrl);
+int hostapd_ctrl_get_fd(struct hostapd_ctrl *ctrl);
+
+#endif /* HOSTAPD_CTRL_H */
diff --git a/contrib/hostapd/iapp.c b/contrib/hostapd/iapp.c
new file mode 100644
index 000000000000..792a4714c4ff
--- /dev/null
+++ b/contrib/hostapd/iapp.c
@@ -0,0 +1,521 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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.
+ */
+
+/* TODO:
+ * Level 1: no administrative or security support
+ * (e.g., static BSSID to IP address mapping in each AP)
+ * Level 2: support for dynamic mapping of BSSID to IP address
+ * Level 3: support for encryption and authentication of IAPP messages
+ * - add support for MOVE-notify and MOVE-response (this requires support for
+ * finding out IP address for previous AP using RADIUS)
+ * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
+ * reassociation to another AP
+ * - implement counters etc. for IAPP MIB
+ * - verify endianness of fields in IAPP messages; are they big-endian as
+ * used here?
+ * - RADIUS connection for AP registration and BSSID to IP address mapping
+ * - TCP connection for IAPP MOVE, CACHE
+ * - broadcast ESP for IAPP ADD-notify
+ * - ESP for IAPP MOVE messages
+ * - security block sending/processing
+ * - IEEE 802.11 context transfer
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#ifdef USE_KERNEL_HEADERS
+#include <linux/if_packet.h>
+#else /* USE_KERNEL_HEADERS */
+#include <netpacket/packet.h>
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "iapp.h"
+#include "eloop.h"
+#include "sta_info.h"
+
+
+#define IAPP_MULTICAST "224.0.1.178"
+#define IAPP_UDP_PORT 3517
+#define IAPP_TCP_PORT 3517
+
+struct iapp_hdr {
+ u8 version;
+ u8 command;
+ u16 identifier;
+ u16 length;
+ /* followed by length-6 octets of data */
+} __attribute__ ((packed));
+
+#define IAPP_VERSION 0
+
+enum IAPP_COMMAND {
+ IAPP_CMD_ADD_notify = 0,
+ IAPP_CMD_MOVE_notify = 1,
+ IAPP_CMD_MOVE_response = 2,
+ IAPP_CMD_Send_Security_Block = 3,
+ IAPP_CMD_ACK_Security_Block = 4,
+ IAPP_CMD_CACHE_notify = 5,
+ IAPP_CMD_CACHE_response = 6,
+};
+
+
+/* ADD-notify - multicast UDP on the local LAN */
+struct iapp_add_notify {
+ u8 addr_len; /* ETH_ALEN */
+ u8 reserved;
+ u8 mac_addr[ETH_ALEN];
+ u16 seq_num;
+} __attribute__ ((packed));
+
+
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+ u8 da[ETH_ALEN]; /* broadcast */
+ u8 sa[ETH_ALEN]; /* STA addr */
+ u16 len; /* 6 */
+ u8 dsap; /* null DSAP address */
+ u8 ssap; /* null SSAP address, CR=Response */
+ u8 control;
+ u8 xid_info[3];
+} __attribute__ ((packed));
+
+
+/* MOVE-notify - unicast TCP */
+struct iapp_move_notify {
+ u8 addr_len; /* ETH_ALEN */
+ u8 reserved;
+ u8 mac_addr[ETH_ALEN];
+ u16 seq_num;
+ u16 ctx_block_len;
+ /* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+
+/* MOVE-response - unicast TCP */
+struct iapp_move_response {
+ u8 addr_len; /* ETH_ALEN */
+ u8 status;
+ u8 mac_addr[ETH_ALEN];
+ u16 seq_num;
+ u16 ctx_block_len;
+ /* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+enum {
+ IAPP_MOVE_SUCCESSFUL = 0,
+ IAPP_MOVE_DENIED = 1,
+ IAPP_MOVE_STALE_MOVE = 2,
+};
+
+
+/* CACHE-notify */
+struct iapp_cache_notify {
+ u8 addr_len; /* ETH_ALEN */
+ u8 reserved;
+ u8 mac_addr[ETH_ALEN];
+ u16 seq_num;
+ u8 current_ap[ETH_ALEN];
+ u16 ctx_block_len;
+ /* ctx_block_len bytes of context block followed by 16-bit context
+ * timeout */
+} __attribute__ ((packed));
+
+
+/* CACHE-response - unicast TCP */
+struct iapp_cache_response {
+ u8 addr_len; /* ETH_ALEN */
+ u8 status;
+ u8 mac_addr[ETH_ALEN];
+ u16 seq_num;
+} __attribute__ ((packed));
+
+enum {
+ IAPP_CACHE_SUCCESSFUL = 0,
+ IAPP_CACHE_STALE_CACHE = 1,
+};
+
+
+/* Send-Security-Block - unicast TCP */
+struct iapp_send_security_block {
+ u8 iv[8];
+ u16 sec_block_len;
+ /* followed by sec_block_len bytes of security block */
+} __attribute__ ((packed));
+
+
+/* ACK-Security-Block - unicast TCP */
+struct iapp_ack_security_block {
+ u8 iv[8];
+ u8 new_ap_ack_authenticator[48];
+} __attribute__ ((packed));
+
+
+struct iapp_data {
+ struct hostapd_data *hapd;
+ u16 identifier; /* next IAPP identifier */
+ struct in_addr own, multicast;
+ int udp_sock;
+ int packet_sock;
+};
+
+
+static void iapp_send_add(struct iapp_data *iapp, u8 *macaddr, u16 seq_num)
+{
+ char buf[128];
+ struct iapp_hdr *hdr;
+ struct iapp_add_notify *add;
+ struct sockaddr_in addr;
+
+ /* Send IAPP ADD-notify to remove possible association from other APs
+ */
+
+ hdr = (struct iapp_hdr *) buf;
+ hdr->version = IAPP_VERSION;
+ hdr->command = IAPP_CMD_ADD_notify;
+ hdr->identifier = host_to_be16(iapp->identifier++);
+ hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
+
+ add = (struct iapp_add_notify *) (hdr + 1);
+ add->addr_len = ETH_ALEN;
+ add->reserved = 0;
+ memcpy(add->mac_addr, macaddr, ETH_ALEN);
+
+ add->seq_num = host_to_be16(seq_num);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = iapp->multicast.s_addr;
+ addr.sin_port = htons(IAPP_UDP_PORT);
+ if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
+ (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ perror("sendto[IAPP-ADD]");
+}
+
+
+static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
+{
+ struct iapp_layer2_update msg;
+
+ /* Send Level 2 Update Frame to update forwarding tables in layer 2
+ * bridge devices */
+
+ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+ memset(msg.da, 0xff, ETH_ALEN);
+ memcpy(msg.sa, addr, ETH_ALEN);
+ msg.len = host_to_be16(6);
+ msg.dsap = 0; /* NULL DSAP address */
+ msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
+ msg.control = 0xaf; /* XID response lsb.1111F101.
+ * F=0 (no poll command; unsolicited frame) */
+ msg.xid_info[0] = 0x81; /* XID format identifier */
+ msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
+ msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
+ * FIX: what is correct RW with 802.11? */
+
+ if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
+ perror("send[L2 Update]");
+}
+
+
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
+{
+ struct ieee80211_mgmt *assoc;
+ u16 seq;
+
+ if (iapp == NULL)
+ return;
+
+ assoc = sta->last_assoc_req;
+ seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
+
+ /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
+ hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
+ HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
+ iapp_send_layer2_update(iapp, sta->addr);
+ iapp_send_add(iapp, sta->addr, seq);
+
+ if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
+ WLAN_FC_STYPE_REASSOC_REQ) {
+ /* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
+ * Context Block, Timeout)
+ */
+ /* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
+ * IP address */
+ }
+}
+
+
+static void iapp_process_add_notify(struct iapp_data *iapp,
+ struct sockaddr_in *from,
+ struct iapp_hdr *hdr, int len)
+{
+ struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
+ struct sta_info *sta;
+
+ if (len != sizeof(*add)) {
+ printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
+ len, (unsigned long) sizeof(*add));
+ return;
+ }
+
+ sta = ap_get_sta(iapp->hapd, add->mac_addr);
+
+ /* IAPP-ADD.indication(MAC Address, Sequence Number) */
+ hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+ HOSTAPD_LEVEL_INFO,
+ "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
+ be_to_host16(add->seq_num),
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port),
+ sta ? "" : " (STA not found)");
+
+ if (!sta)
+ return;
+
+ /* TODO: could use seq_num to try to determine whether last association
+ * to this AP is newer than the one advertised in IAPP-ADD. Although,
+ * this is not really a reliable verification. */
+
+ hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+ HOSTAPD_LEVEL_DEBUG,
+ "Removing STA due to IAPP ADD-notify");
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+ eloop_cancel_timeout(ap_handle_timer, iapp->hapd, sta);
+ eloop_register_timeout(0, 0, ap_handle_timer, iapp->hapd, sta);
+ sta->timeout_next = STA_REMOVE;
+}
+
+
+static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct iapp_data *iapp = eloop_ctx;
+ int len, hlen;
+ unsigned char buf[128];
+ struct sockaddr_in from;
+ socklen_t fromlen;
+ struct iapp_hdr *hdr;
+
+ /* Handle incoming IAPP frames (over UDP/IP) */
+
+ fromlen = sizeof(from);
+ len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (len < 0)
+ perror("recvfrom");
+
+ if (from.sin_addr.s_addr == iapp->own.s_addr)
+ return; /* ignore own IAPP messages */
+
+ hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+ HOSTAPD_LEVEL_DEBUG,
+ "Received %d byte IAPP frame from %s%s\n",
+ len, inet_ntoa(from.sin_addr),
+ len < sizeof(*hdr) ? " (too short)" : "");
+
+ if (len < sizeof(*hdr))
+ return;
+
+ hdr = (struct iapp_hdr *) buf;
+ hlen = be_to_host16(hdr->length);
+ hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+ HOSTAPD_LEVEL_DEBUG,
+ "RX: version=%d command=%d id=%d len=%d\n",
+ hdr->version, hdr->command,
+ be_to_host16(hdr->identifier), hlen);
+ if (hdr->version != IAPP_VERSION) {
+ printf("Dropping IAPP frame with unknown version %d\n",
+ hdr->version);
+ return;
+ }
+ if (hlen > len) {
+ printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+ return;
+ }
+ if (hlen < len) {
+ printf("Ignoring %d extra bytes from IAPP frame\n",
+ len - hlen);
+ len = hlen;
+ }
+
+ switch (hdr->command) {
+ case IAPP_CMD_ADD_notify:
+ iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+ break;
+ case IAPP_CMD_MOVE_notify:
+ /* TODO: MOVE is using TCP; so move this to TCP handler once it
+ * is implemented.. */
+ /* IAPP-MOVE.indication(MAC Address, New BSSID,
+ * Sequence Number, AP Address, Context Block) */
+ /* TODO: process */
+ break;
+ default:
+ printf("Unknown IAPP command %d\n", hdr->command);
+ break;
+ }
+}
+
+
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ int ifindex;
+ struct sockaddr_in *paddr, uaddr;
+ struct iapp_data *iapp;
+ struct ip_mreqn mreq;
+
+ iapp = malloc(sizeof(*iapp));
+ if (iapp == NULL)
+ return NULL;
+ memset(iapp, 0, sizeof(*iapp));
+ iapp->hapd = hapd;
+ iapp->udp_sock = iapp->packet_sock = -1;
+
+ /* TODO:
+ * open socket for sending and receiving IAPP frames over TCP
+ */
+
+ iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (iapp->udp_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ iapp_deinit(iapp);
+ return NULL;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+ if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ iapp_deinit(iapp);
+ return NULL;
+ }
+ ifindex = ifr.ifr_ifindex;
+
+ if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFADDR)");
+ iapp_deinit(iapp);
+ return NULL;
+ }
+ paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+ if (paddr->sin_family != AF_INET) {
+ printf("Invalid address family %i (SIOCGIFADDR)\n",
+ paddr->sin_family);
+ iapp_deinit(iapp);
+ return NULL;
+ }
+ iapp->own.s_addr = paddr->sin_addr.s_addr;
+
+ if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFBRDADDR)");
+ iapp_deinit(iapp);
+ return NULL;
+ }
+ paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+ if (paddr->sin_family != AF_INET) {
+ printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
+ paddr->sin_family);
+ iapp_deinit(iapp);
+ return NULL;
+ }
+ inet_aton(IAPP_MULTICAST, &iapp->multicast);
+
+ memset(&uaddr, 0, sizeof(uaddr));
+ uaddr.sin_family = AF_INET;
+ uaddr.sin_port = htons(IAPP_UDP_PORT);
+ if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
+ sizeof(uaddr)) < 0) {
+ perror("bind[UDP]");
+ iapp_deinit(iapp);
+ return NULL;
+ }
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = iapp->multicast;
+ mreq.imr_address.s_addr = INADDR_ANY;
+ mreq.imr_ifindex = 0;
+ if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq)) < 0) {
+ perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+ return NULL;
+ }
+
+ iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (iapp->packet_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return NULL;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifindex;
+ if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ perror("bind[PACKET]");
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
+ iapp, NULL)) {
+ printf("Could not register read socket for IAPP.\n");
+ return NULL;
+ }
+
+ printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+
+ /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
+ * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
+ * be openned only after receiving Initiate-Accept. If Initiate-Reject
+ * is received, IAPP is not started. */
+
+ return iapp;
+}
+
+
+void iapp_deinit(struct iapp_data *iapp)
+{
+ struct ip_mreqn mreq;
+
+ if (iapp == NULL)
+ return;
+
+ if (iapp->udp_sock >= 0) {
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = iapp->multicast;
+ mreq.imr_address.s_addr = INADDR_ANY;
+ mreq.imr_ifindex = 0;
+ if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+ }
+
+ eloop_unregister_read_sock(iapp->udp_sock);
+ close(iapp->udp_sock);
+ }
+ if (iapp->packet_sock >= 0) {
+ eloop_unregister_read_sock(iapp->packet_sock);
+ close(iapp->packet_sock);
+ }
+ free(iapp);
+}
diff --git a/contrib/hostapd/iapp.h b/contrib/hostapd/iapp.h
new file mode 100644
index 000000000000..d6e8f6570e2b
--- /dev/null
+++ b/contrib/hostapd/iapp.h
@@ -0,0 +1,31 @@
+#ifndef IAPP_H
+#define IAPP_H
+
+struct iapp_data;
+
+#ifdef CONFIG_IAPP
+
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
+void iapp_deinit(struct iapp_data *iapp);
+
+#else /* CONFIG_IAPP */
+
+static inline void iapp_new_station(struct iapp_data *iapp,
+ struct sta_info *sta)
+{
+}
+
+static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
+ const char *iface)
+{
+ return NULL;
+}
+
+static inline void iapp_deinit(struct iapp_data *iapp)
+{
+}
+
+#endif /* CONFIG_IAPP */
+
+#endif /* IAPP_H */
diff --git a/contrib/hostapd/ieee802_11.c b/contrib/hostapd/ieee802_11.c
new file mode 100644
index 000000000000..16a3d0e7741c
--- /dev/null
+++ b/contrib/hostapd/ieee802_11.c
@@ -0,0 +1,1217 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver / IEEE 802.11 Management
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#include "eloop.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "radius.h"
+#include "radius_client.h"
+#include "ieee802_11_auth.h"
+#include "sta_info.h"
+#include "eapol_sm.h"
+#include "rc4.h"
+#include "ieee802_1x.h"
+#include "wpa.h"
+#include "accounting.h"
+#include "driver.h"
+
+
+static u8 * hostapd_eid_supp_rates(hostapd *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = 4; /* len */
+ *pos++ = 0x82; /* 1 Mbps, base set */
+ *pos++ = 0x84; /* 2 Mbps, base set */
+ *pos++ = 0x0b; /* 5.5 Mbps */
+ *pos++ = 0x16; /* 11 Mbps */
+
+ return pos;
+}
+
+
+static u16 hostapd_own_capab_info(hostapd *hapd)
+{
+ int capab = WLAN_CAPABILITY_ESS;
+ if (hapd->conf->wpa ||
+ (hapd->conf->ieee802_1x &&
+ (hapd->conf->default_wep_key_len ||
+ hapd->conf->individual_wep_key_len)))
+ capab |= WLAN_CAPABILITY_PRIVACY;
+ return capab;
+}
+
+
+static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+
+ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
+ size_t len,
+ struct ieee802_11_elems *elems,
+ int show_errors)
+{
+ size_t left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left) {
+ if (show_errors) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "IEEE 802.11 element parse "
+ "failed (id=%d elen=%d "
+ "left=%lu)\n",
+ id, elen, (unsigned long) left);<