Re-initialize hostapd/wpa_supplicant git repository based on 0.6.3 release
This commit is contained in:
commit
6fc6879bd5
589 changed files with 213408 additions and 0 deletions
340
COPYING
Normal file
340
COPYING
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
181
FAQ
Normal file
181
FAQ
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
Host AP driver - Frequently Asked Questions
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
|
||||||
|
2. Why RX does not work?
|
||||||
|
What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
|
||||||
|
(interrupt delivery problems)
|
||||||
|
3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
|
||||||
|
4. What is causing 'Unresolved symbols' in depmod/modprobe?
|
||||||
|
5. How can I upgrade Prism2/2.5/3 firmware?
|
||||||
|
6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
|
||||||
|
only one wireless card?
|
||||||
|
7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
|
||||||
|
card with small flash) card fail?
|
||||||
|
8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
|
||||||
|
chipsets other than Prism 2/2.5/3?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1. What does "GetNextTuple: No more items" mean in hostap_cs initialization?
|
||||||
|
|
||||||
|
This is one of the most often reported problems in getting the
|
||||||
|
hostap_cs.o driver working. It is usually reported for D-Link DWL-650
|
||||||
|
PC Card, e.g., on ISA-to-PCMCIA adapter. Later versions of the driver
|
||||||
|
report this also with "Vcc mismatch - skipping this entry".
|
||||||
|
|
||||||
|
Most common reason for getting this is a mismatch in voltage
|
||||||
|
configuration. The driver tries to make sure that the voltage (Vcc)
|
||||||
|
configuration in CIS and the slot match each other. It refuses to
|
||||||
|
initialize the card if the card CIS does not include a CFTABLE entry
|
||||||
|
with a matching Vcc value. This seems to be a problem for some cases
|
||||||
|
since the CIS is invalid or the reported voltage is incorrect.
|
||||||
|
|
||||||
|
As a workaround, the driver supports a module parameter ignore_cis_vcc
|
||||||
|
that can be used to skip this verification. This can be enabled by
|
||||||
|
setting ignore_cis_vcc=1 in /etc/pcmcia/hostap_cs.conf (commented
|
||||||
|
example line in the end of file). This can also be tested by manually
|
||||||
|
loading the module with 'modprobe hostap_cs ignore_cis_vcc=1' before
|
||||||
|
inserting the card).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2. Why RX does not work?
|
||||||
|
What does "NETDEV WATCHDOG: wlan0: transmit timed out" mean?
|
||||||
|
(interrupt delivery problems)
|
||||||
|
|
||||||
|
If the driver does not seem to receive any packets or sending packets
|
||||||
|
results in "NETDEV WATCHDOG: wlan0: transmit timed out", the reason is
|
||||||
|
probably in interrupt delivery problems. This is quite common with
|
||||||
|
PCI-to-PCMCIA adapters. Newer than 2002-05-19 of the driver have a
|
||||||
|
test that will report this after the initialization ("wlan: Possible
|
||||||
|
interrupt delivery problem"). Another method for checking this is to
|
||||||
|
observer whether interrupt counters in /proc/interrupts increase for
|
||||||
|
hostap_cs/wlan0 entry.
|
||||||
|
|
||||||
|
Adding suitable irq_mode=# setting in PCIC_OPTS line of
|
||||||
|
pcmcia-configuration is the most common fix for this. pcmcia-cs HOWTO
|
||||||
|
has more information on how to debug and fix interrupt delivery
|
||||||
|
problems at
|
||||||
|
http://pcmcia-cs.sourceforge.net/ftp/doc/PCMCIA-HOWTO-5.html#irqmode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3. What is wrong with Host AP mode in secondary (station) firmware v1.4.2?
|
||||||
|
|
||||||
|
It looks like secondary firmware v1.4.2 sends beacon frames properly,
|
||||||
|
but does not respond to probe requests. With most station cards, this
|
||||||
|
prevents authentication and association and thus, in practice, no data
|
||||||
|
frames can be sent. It has been reported that at least some Cisco
|
||||||
|
Aironet 350 cards can associate with Host AP mode even with firmware
|
||||||
|
v1.4.2 (i.e., without receiving probe response), but Prism2 and
|
||||||
|
Lucent/ORiNOCO/Agere seem to require probe response and they do not
|
||||||
|
thus associate with AP using v1.4.2 firmware.
|
||||||
|
|
||||||
|
This is fixed in later secondary firmware versions; probably already
|
||||||
|
in 1.4.3, but at least 1.4.9 has been tested to work. In other words,
|
||||||
|
this problem can be fixed by upgrading card firmware.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
4. What is causing 'Unresolved symbols' in depmod/modprobe?
|
||||||
|
|
||||||
|
Installation of Host AP driver (e.g, 'make install_pccard') may report
|
||||||
|
unresolved symbols when running depmod. These are usually caused with
|
||||||
|
mismatch in kernel configuration for modversions.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
depmod reports unresolved symbol 'eth_type_trans' (this is without
|
||||||
|
modversions):
|
||||||
|
depmod: eth_type_trans
|
||||||
|
|
||||||
|
but kernel was really configured with CONFIG_MODVERSIONS:
|
||||||
|
|
||||||
|
# grep eth_type_trans /proc/ksyms
|
||||||
|
c01b66c0 eth_type_trans_Rdb9cd26f
|
||||||
|
|
||||||
|
(notice the _R... postfix)
|
||||||
|
|
||||||
|
This happens if the kernel configuration given to Host AP driver's
|
||||||
|
Makefile (.config in KERNEL_PATH) has not CONFIG_MODVERSIONS, but the
|
||||||
|
running kernel is compiled with it.
|
||||||
|
If the kernel were configured without modversions, /proc/ksyms would
|
||||||
|
show the symbols with _R... postfix:
|
||||||
|
|
||||||
|
|
||||||
|
Mismatches in kernel configuration can be fixed by using the same
|
||||||
|
configuration (i.e., Linux kernel .config) for both the kernel and the
|
||||||
|
driver. If you are using a kernel from a distribution installation
|
||||||
|
(i.e., you have not compiled it yourself), you will need to create a
|
||||||
|
matching .config file somehow. This depends on the distribution you
|
||||||
|
are using, but 'make oldconfig' in kernel source directory might work
|
||||||
|
with some distributions. If you compile the kernel yourself, it will
|
||||||
|
be easier, since you already have to have created the correct .config
|
||||||
|
file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5. How can I upgrade Prism2/2.5/3 firmware?
|
||||||
|
|
||||||
|
Prism2/2.5/3 cards and Host AP driver support two different mechanism
|
||||||
|
of upgrading the card firmware. Firmware images (primary and station)
|
||||||
|
can be downloaded either into volatile memory (RAM download) or
|
||||||
|
non-volatile memory (flash upgrade). Firmware images downloaded into
|
||||||
|
volatile memory are lost when the card is resetted, so they are quite
|
||||||
|
safe. Flash upgrade with incorrect images may cause permanent problems
|
||||||
|
(i.e., render the card useless), so certain amount of caution is
|
||||||
|
always recommended for this.
|
||||||
|
|
||||||
|
Note! Some of the older versions of Host AP driver or prism2_srec had
|
||||||
|
fatal bugs in flash upgrade. Only versions 0.1.0 or newer should be
|
||||||
|
used when performing non-volatile flash upgrade!
|
||||||
|
|
||||||
|
utils/prism2_srec (run 'make' in utils directory to build this) is a
|
||||||
|
tool that can be instructed Host AP driver to download firmware image
|
||||||
|
into the wlan card. Brief usage information is available by running
|
||||||
|
this program without any command line parameters. Please note, that
|
||||||
|
the downloading support is disabled in the default Host AP driver
|
||||||
|
build. You will need to change this by defining
|
||||||
|
PRISM2_DOWNLOAD_SUPPORT (and PRISM2_NON_VOLATILE_DOWNLOAD if you want
|
||||||
|
to update flash); see driver/modules/hostap_config.h for more details.
|
||||||
|
|
||||||
|
Jun Sun has written a mini-howto on flashing Intersil Prism
|
||||||
|
Chipsets. This is available at http://linux.junsun.net/intersil-prism/.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
6. Why did I get two network interfaces (wlan0 and wifi0) even when I have
|
||||||
|
only one wireless card?
|
||||||
|
|
||||||
|
Host AP driver supports multiple virtual interfaces per wireless
|
||||||
|
card. wifi0 is the master radio interface and wlan0 is the first
|
||||||
|
virtual interface for this radio. Other virtual interfaces are wlan0ap
|
||||||
|
(for hostapd), and one interface per WDS link.
|
||||||
|
|
||||||
|
In most cases, one should ignore wifi0 interface and just use wlan0
|
||||||
|
interface. In other words, assign IP address to wlan0, not wifi0 and
|
||||||
|
in general, just ignore the wifi0 interface.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
7. Why does my D-Link DWL-650 rev. P1 or D-Link DWL-520 rev. E1 (or any other
|
||||||
|
card with small flash) card fail?
|
||||||
|
|
||||||
|
Some of the new Prism3-based cards use a smaller flash chip that does
|
||||||
|
not include full firmware for the card. For example, D-Link DWL-650
|
||||||
|
rev. P1 and D-Link DWL-520 rev. E1 are such cards. These cards require
|
||||||
|
that the firmware is downloaded to the card during initialization. See
|
||||||
|
utils/hostap_fw_load for example commands on doing this.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
8. Does Host AP driver support IEEE 802.11a and 802.11g? Does it support
|
||||||
|
chipsets other than Prism 2/2.5/3?
|
||||||
|
|
||||||
|
Host AP driver supports only Intersil Prism chipsets, versions 2, 2.5,
|
||||||
|
and 3. Those chipsets support IEEE 802.11b only; other chipsets are
|
||||||
|
not supported. All utilities distributed with Host AP driver except
|
||||||
|
wpa_supplicant work only with Host AP driver, so they are limited to
|
||||||
|
the same hardware. wpa_supplicant works with other drivers, including
|
||||||
|
those that support 802.11a and 802.11g.
|
19
README
Normal file
19
README
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
wpa_supplicant and hostapd v0.6.x
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
|
||||||
|
All Rights Reserved.
|
||||||
|
|
||||||
|
These program is dual-licensed under both the GPL version 2 and BSD
|
||||||
|
license. Either license may be used at your option.
|
||||||
|
|
||||||
|
|
||||||
|
This package may include either wpa_supplicant, hostapd, or both. See
|
||||||
|
README file respective subdirectories (wpa_supplicant/README or
|
||||||
|
hostapd/README) for more details.
|
||||||
|
|
||||||
|
Source code files have been moved around in v0.6.x releases and
|
||||||
|
compared to earlier releases, the programs are now build by first
|
||||||
|
going to a subdirectory (wpa_supplicant or hostapd) and creating
|
||||||
|
build configuration (.config) and running 'make' there (for
|
||||||
|
Linux/BSD/cygwin builds).
|
143
build_release
Executable file
143
build_release
Executable file
|
@ -0,0 +1,143 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Path to the Windows cross compiler (mingw)
|
||||||
|
WINCROSS=/opt/xmingw/bin
|
||||||
|
WINLOCAL=/home/jm/H-win/local
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "build_release <version> [nobin]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP=tmp.build_release
|
||||||
|
RELDIR=`pwd`/Release
|
||||||
|
VER=$1
|
||||||
|
NOW=`date +%Y-%m-%d`
|
||||||
|
|
||||||
|
echo "Version: $VER - $NOW"
|
||||||
|
|
||||||
|
DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||||
|
DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
|
||||||
|
|
||||||
|
if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
|
||||||
|
echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -r $TMP ]; then
|
||||||
|
echo "Temporary directory '$TMP' exists. Remove it before running this."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir $TMP
|
||||||
|
mkdir -p $RELDIR
|
||||||
|
|
||||||
|
git-archive --format=tar --prefix=wpa-$VER/ HEAD \
|
||||||
|
README COPYING patches src wpa_supplicant hostapd |
|
||||||
|
gzip > $RELDIR/wpa-$VER.tar.gz
|
||||||
|
git-archive --format=tar --prefix=hostapd-$VER/ HEAD \
|
||||||
|
README COPYING patches src hostapd |
|
||||||
|
gzip > $RELDIR/hostapd-$VER.tar.gz
|
||||||
|
git-archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
|
||||||
|
README COPYING patches src wpa_supplicant |
|
||||||
|
tar --directory=$TMP -xf -
|
||||||
|
|
||||||
|
cd $TMP
|
||||||
|
make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
|
||||||
|
rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
|
||||||
|
tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
|
||||||
|
cd ..
|
||||||
|
rm -r $TMP
|
||||||
|
|
||||||
|
if [ "$2" == "nobin" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d $WINCROSS ]; then
|
||||||
|
pushd $RELDIR
|
||||||
|
|
||||||
|
PDIR=wpa_supplicant-$VER
|
||||||
|
WDIR=wpa_supplicant-windows-bin-$VER
|
||||||
|
tar xzf $PDIR.tar.gz
|
||||||
|
mkdir "$WDIR"
|
||||||
|
cd "$PDIR/wpa_supplicant"
|
||||||
|
cat > .config <<EOF
|
||||||
|
CONFIG_DRIVER_NDIS=y
|
||||||
|
CONFIG_NATIVE_WINDOWS=y
|
||||||
|
|
||||||
|
CFLAGS += -I/opt/xmingw/i386-mingw32msvc/include/ddk
|
||||||
|
CC=i386-mingw32msvc-gcc
|
||||||
|
STRIP=i386-mingw32msvc-strip
|
||||||
|
PLATFORMSDKLIB=$WINLOCAL/lib
|
||||||
|
CONFIG_NDIS_EVENTS_INTEGRATED=y
|
||||||
|
|
||||||
|
CFLAGS += -I$WINLOCAL/include
|
||||||
|
LIBS += -L$WINLOCAL/lib
|
||||||
|
LIBS_w += -L$WINLOCAL/lib
|
||||||
|
LIBS_p += -L$WINLOCAL/lib
|
||||||
|
|
||||||
|
CONFIG_EAP_SIM=y
|
||||||
|
CONFIG_EAP_AKA=y
|
||||||
|
CONFIG_EAP_LEAP=y
|
||||||
|
CONFIG_EAP_FAST=y
|
||||||
|
CONFIG_EAP_TLS=y
|
||||||
|
|
||||||
|
CONFIG_CTRL_IFACE=y
|
||||||
|
CONFIG_EAP_FAST=y
|
||||||
|
CONFIG_EAP_MSCHAPV2=y
|
||||||
|
CONFIG_EAP_TTLS=y
|
||||||
|
CONFIG_EAP_PEAP=y
|
||||||
|
CONFIG_EAP_MD5=y
|
||||||
|
CONFIG_EAP_GTC=y
|
||||||
|
CONFIG_EAP_OTP=y
|
||||||
|
CONFIG_EAP_PAX=y
|
||||||
|
CONFIG_EAP_SAKE=y
|
||||||
|
CONFIG_EAP_PSK=y
|
||||||
|
CONFIG_EAP_TNC=y
|
||||||
|
CONFIG_PKCS12=y
|
||||||
|
CONFIG_PCSC=y
|
||||||
|
|
||||||
|
CONFIG_L2_PACKET=winpcap
|
||||||
|
CONFIG_MAIN=main_winsvc
|
||||||
|
CONFIG_BACKEND=winreg
|
||||||
|
CONFIG_ELOOP=eloop_win
|
||||||
|
CFLAGS += -DCONFIG_DEBUG_FILE
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# First, build the Windows service & registry version and rename it
|
||||||
|
PATH=$PATH:$WINCROSS make windows-bin
|
||||||
|
mv wpa_supplicant.exe wpasvc.exe
|
||||||
|
|
||||||
|
# Then, build "the standard" wpa_supplicant.exe
|
||||||
|
cat >> .config <<EOF
|
||||||
|
CONFIG_MAIN=main
|
||||||
|
CONFIG_BACKEND=file
|
||||||
|
EOF
|
||||||
|
|
||||||
|
PATH=$PATH:$WINCROSS make windows-bin
|
||||||
|
|
||||||
|
for i in COPYING; do
|
||||||
|
unix2dos < ../$i > ../../"$WDIR"/$i
|
||||||
|
done
|
||||||
|
for i in README README-Windows.txt wpa_supplicant.conf; do
|
||||||
|
unix2dos < $i > ../../"$WDIR"/$i
|
||||||
|
done
|
||||||
|
mv *.exe ../../"$WDIR"
|
||||||
|
cp win_example.reg ../../"$WDIR"
|
||||||
|
|
||||||
|
cd wpa_gui-qt4
|
||||||
|
PATH=$PATH:$WINCROSS ./setup-mingw-cross-compiling
|
||||||
|
PATH=$PATH:$WINCROSS make
|
||||||
|
cp release/wpa_gui.exe ../../../"$WDIR"
|
||||||
|
cd ../../..
|
||||||
|
rm -rf "$PDIR"
|
||||||
|
zip "$WDIR.zip" "$WDIR"/*
|
||||||
|
rm -rf "$WDIR"
|
||||||
|
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
ls -l $RELDIR/*$VER*
|
||||||
|
|
||||||
|
exit 0
|
3
eap_example/.gitignore
vendored
Normal file
3
eap_example/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.d
|
||||||
|
eap_example
|
||||||
|
libeap.so
|
179
eap_example/Makefile
Normal file
179
eap_example/Makefile
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
ALL=eap_example
|
||||||
|
|
||||||
|
all: $(ALL)
|
||||||
|
|
||||||
|
ifndef CC
|
||||||
|
CC=gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CFLAGS
|
||||||
|
CFLAGS = -MMD -O2 -Wall -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
CONFIG_TLS=openssl
|
||||||
|
#CONFIG_TLS=internal
|
||||||
|
#CONFIG_INTERNAL_LIBTOMMATH=y
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS += -I.
|
||||||
|
CFLAGS += -I../src
|
||||||
|
CFLAGS += -I../src/crypto
|
||||||
|
CFLAGS += -I../src/utils
|
||||||
|
CFLAGS += -I../src/common
|
||||||
|
|
||||||
|
# at least for now, need to include config_ssid.h and config_blob.h from
|
||||||
|
# wpa_supplicant directory
|
||||||
|
CFLAGS += -I../wpa_supplicant
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_both += ../src/utils/common.o
|
||||||
|
OBJS_both += ../src/utils/os_unix.o
|
||||||
|
OBJS_both += ../src/utils/wpa_debug.o
|
||||||
|
OBJS_both += ../src/utils/base64.o
|
||||||
|
OBJS_both += ../src/utils/wpabuf.o
|
||||||
|
OBJS_both += ../src/crypto/md5.o
|
||||||
|
OBJS_both += ../src/crypto/rc4.o
|
||||||
|
OBJS_both += ../src/crypto/md4.o
|
||||||
|
OBJS_both += ../src/crypto/sha1.o
|
||||||
|
OBJS_both += ../src/crypto/des.o
|
||||||
|
OBJS_both += ../src/crypto/aes_wrap.o
|
||||||
|
OBJS_both += ../src/crypto/aes.o
|
||||||
|
OBJS_both += ../src/crypto/ms_funcs.o
|
||||||
|
OBJS_both += ../src/crypto/sha256.o
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_both += ../src/eap_common/eap_psk_common.o
|
||||||
|
OBJS_both += ../src/eap_common/eap_pax_common.o
|
||||||
|
OBJS_both += ../src/eap_common/eap_sake_common.o
|
||||||
|
OBJS_both += ../src/eap_common/eap_gpsk_common.o
|
||||||
|
OBJS_both += ../src/eap_common/chap.o
|
||||||
|
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_tls.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_peap.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_ttls.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_md5.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_mschapv2.o
|
||||||
|
OBJS_peer += ../src/eap_peer/mschapv2.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_otp.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_gtc.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_leap.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_psk.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_tlv.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_pax.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_sake.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_gpsk.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap.o
|
||||||
|
OBJS_peer += ../src/eap_common/eap_common.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_methods.o
|
||||||
|
OBJS_peer += ../src/eap_peer/eap_tls_common.o
|
||||||
|
|
||||||
|
CFLAGS += -DEAP_TLS
|
||||||
|
CFLAGS += -DEAP_PEAP
|
||||||
|
CFLAGS += -DEAP_TTLS
|
||||||
|
CFLAGS += -DEAP_MD5
|
||||||
|
CFLAGS += -DEAP_MSCHAPv2
|
||||||
|
CFLAGS += -DEAP_GTC
|
||||||
|
CFLAGS += -DEAP_OTP
|
||||||
|
CFLAGS += -DEAP_LEAP
|
||||||
|
CFLAGS += -DEAP_PSK
|
||||||
|
CFLAGS += -DEAP_TLV
|
||||||
|
CFLAGS += -DEAP_PAX
|
||||||
|
CFLAGS += -DEAP_SAKE
|
||||||
|
CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
|
||||||
|
CFLAGS += -DEAP_TLS_FUNCS
|
||||||
|
|
||||||
|
CFLAGS += -DIEEE8021X_EAPOL
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_TLS), openssl)
|
||||||
|
CFLAGS += -DEAP_TLS_OPENSSL
|
||||||
|
OBJS_both += ../src/crypto/tls_openssl.o
|
||||||
|
OBJS_both += ../src/crypto/crypto_openssl.o
|
||||||
|
LIBS += -lssl -lcrypto
|
||||||
|
CFLAGS += -DINTERNAL_SHA256
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_TLS), internal)
|
||||||
|
OBJS_both += ../src/crypto/tls_internal.o
|
||||||
|
OBJS_both += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
|
||||||
|
OBJS_both += ../src/tls/tlsv1_cred.o
|
||||||
|
OBJS_both += ../src/tls/asn1.o ../src/tls/x509v3.o
|
||||||
|
OBJS_both += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
|
||||||
|
|
||||||
|
OBJS_peer += ../src/tls/tlsv1_client.o
|
||||||
|
OBJS_peer += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
|
||||||
|
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
|
||||||
|
|
||||||
|
OBJS_server += ../src/tls/tlsv1_server.o
|
||||||
|
OBJS_server += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
|
||||||
|
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
|
||||||
|
|
||||||
|
CFLAGS += -DCONFIG_TLS_INTERNAL
|
||||||
|
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
|
||||||
|
CFLAGS += -DCONFIG_INTERNAL_X509
|
||||||
|
CFLAGS += -DINTERNAL_AES
|
||||||
|
CFLAGS += -DINTERNAL_SHA1
|
||||||
|
CFLAGS += -DINTERNAL_SHA256
|
||||||
|
CFLAGS += -DINTERNAL_MD5
|
||||||
|
CFLAGS += -DINTERNAL_MD4
|
||||||
|
CFLAGS += -DINTERNAL_DES
|
||||||
|
ifdef CONFIG_INTERNAL_LIBTOMMATH
|
||||||
|
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
|
||||||
|
else
|
||||||
|
LIBS += -ltommath
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Optional components to add EAP server support
|
||||||
|
OBJS_server += ../src/eap_server/eap_tls.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_peap.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_ttls.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_md5.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_mschapv2.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_gtc.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_psk.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_tlv.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_pax.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_sake.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_gpsk.o
|
||||||
|
OBJS_server += ../src/eap_server/eap.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_identity.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_methods.o
|
||||||
|
OBJS_server += ../src/eap_server/eap_tls_common.o
|
||||||
|
CFLAGS += -DEAP_SERVER
|
||||||
|
|
||||||
|
|
||||||
|
ifndef LDO
|
||||||
|
LDO=$(CC)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
|
||||||
|
|
||||||
|
OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_SOLIB), yes)
|
||||||
|
LIBEAP = libeap.a
|
||||||
|
libeap.a: $(OBJS_lib)
|
||||||
|
ar rc libeap.a $(OBJS_lib)
|
||||||
|
ranlib libeap.a
|
||||||
|
|
||||||
|
else
|
||||||
|
CFLAGS += -fPIC -DPIC
|
||||||
|
LDFLAGS += -shared
|
||||||
|
|
||||||
|
LIBEAP = libeap.so
|
||||||
|
libeap.so: $(OBJS_lib)
|
||||||
|
$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
eap_example: $(OBJS_ex) $(LIBEAP)
|
||||||
|
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C ../src clean
|
||||||
|
rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
|
||||||
|
|
||||||
|
-include $(OBJS:%.o=%.d)
|
46
eap_example/README
Normal file
46
eap_example/README
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
EAP peer/server library and example program
|
||||||
|
Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License version 2 as
|
||||||
|
published by the Free Software Foundation.
|
||||||
|
|
||||||
|
Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
license.
|
||||||
|
|
||||||
|
|
||||||
|
The interfaces of the EAP server/peer implementation are based on RFC
|
||||||
|
4137 (EAP State Machines). This RFC is coordinated with the state
|
||||||
|
machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
|
||||||
|
include implementation of the IEEE 802.1X EAPOL state machines and the
|
||||||
|
interface between them and EAP. However, the EAP implementation can be
|
||||||
|
used with other protocols, too, by providing a compatible interface
|
||||||
|
which maps the EAPOL<->EAP variables to another protocol.
|
||||||
|
|
||||||
|
This directory contains an example showing how EAP peer and server
|
||||||
|
code from wpa_supplicant and hostapd can be used as a library. The
|
||||||
|
example program initializes both an EAP server and an EAP peer
|
||||||
|
entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
|
||||||
|
|
||||||
|
eap_example_peer.c shows the initialization and glue code needed to
|
||||||
|
control the EAP peer implementation. eap_example_server.c does the
|
||||||
|
same for EAP server. eap_example.c is an example that ties in both the
|
||||||
|
EAP server and client parts to allow an EAP authentication to be
|
||||||
|
shown.
|
||||||
|
|
||||||
|
In this example, the EAP messages are passed between the server and
|
||||||
|
the peer are passed by direct function calls within the same process.
|
||||||
|
In practice, server and peer functionalities would likely reside in
|
||||||
|
separate devices and the EAP messages would be transmitted between the
|
||||||
|
devices based on an external protocol. For example, in IEEE 802.11
|
||||||
|
uses IEEE 802.1X EAPOL state machines to control the transmission of
|
||||||
|
EAP messages and WiMax supports optional PMK EAP authentication
|
||||||
|
mechanism that transmits EAP messages as defined in IEEE 802.16e.
|
||||||
|
|
||||||
|
|
||||||
|
The EAP library links in number of helper functions from src/utils and
|
||||||
|
src/crypto directories. Most of these are suitable as-is, but it may
|
||||||
|
be desirable to replace the debug output code in src/utils/wpa_debug.c
|
||||||
|
by dropping this file from the library and re-implementing the
|
||||||
|
functions there in a way that better fits in with the main
|
||||||
|
application.
|
19
eap_example/ca.pem
Normal file
19
eap_example/ca.pem
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDBzCCAnCgAwIBAgIJAIb4NS4TdLXUMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
|
||||||
|
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
|
||||||
|
A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
|
||||||
|
MTIwOTAzMTQzN1oXDTE3MTIwNjAzMTQzN1owYTELMAkGA1UEBhMCVVMxEzARBgNV
|
||||||
|
BAgTCkNhbGlmb3JuaWExDjAMBgNVBAoTBXcxLmZpMRAwDgYDVQQDEwdUZXN0IENB
|
||||||
|
MRswGQYJKoZIhvcNAQkBFgx0ZXN0Y2FAdzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQAD
|
||||||
|
gY0AMIGJAoGBAO6GoecRclnILh9FTvqnY/yUZmeJDgC+3/PQiicpMDhAzCkWAmi+
|
||||||
|
a1LSnqakNN/GdCy3q053TFLFEzhEHkhhRwY/zzj2vZIcFZESoUhr67CzCpcPmTGa
|
||||||
|
AfOzsGPjaH6xYcaOR4RZMfXd/EKfAauHxj3LuCusLL5hK/FwxWhQJNJrAgMBAAGj
|
||||||
|
gcYwgcMwHQYDVR0OBBYEFKhJuSLJ6JhcB/dRgB8j0h9mOlpKMIGTBgNVHSMEgYsw
|
||||||
|
gYiAFKhJuSLJ6JhcB/dRgB8j0h9mOlpKoWWkYzBhMQswCQYDVQQGEwJVUzETMBEG
|
||||||
|
A1UECBMKQ2FsaWZvcm5pYTEOMAwGA1UEChMFdzEuZmkxEDAOBgNVBAMTB1Rlc3Qg
|
||||||
|
Q0ExGzAZBgkqhkiG9w0BCQEWDHRlc3RjYUB3MS5maYIJAIb4NS4TdLXUMAwGA1Ud
|
||||||
|
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuU+5Uerq+n8WgiIsiANT3wUoGe2Y
|
||||||
|
cnoQi2nVjUHrivgMDufH0tgh1AVfc3wVNNREdGC136qr1KBNqalQx2rKZ76xeNqW
|
||||||
|
sQa2LIC2wE7Q7LJsltUcUjPyZHGUhBqWjKsCvlonfNB6JHkEayTEvVvyupgzTsxW
|
||||||
|
QuuRdZ0sNv/S8VI=
|
||||||
|
-----END CERTIFICATE-----
|
55
eap_example/eap_example.c
Normal file
55
eap_example/eap_example.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Example application showing how EAP peer and server code from
|
||||||
|
* wpa_supplicant/hostapd can be used as a library. This example program
|
||||||
|
* initializes both an EAP server and an EAP peer entities and then runs
|
||||||
|
* through an EAP-PEAP/MSCHAPv2 authentication.
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
int eap_example_peer_init(void);
|
||||||
|
void eap_example_peer_deinit(void);
|
||||||
|
int eap_example_peer_step(void);
|
||||||
|
|
||||||
|
int eap_example_server_init(void);
|
||||||
|
void eap_example_server_deinit(void);
|
||||||
|
int eap_example_server_step(void);
|
||||||
|
|
||||||
|
|
||||||
|
extern int wpa_debug_level;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int res_s, res_p;
|
||||||
|
|
||||||
|
wpa_debug_level = 0;
|
||||||
|
|
||||||
|
if (eap_example_peer_init() < 0 ||
|
||||||
|
eap_example_server_init() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
printf("---[ server ]--------------------------------\n");
|
||||||
|
res_s = eap_example_server_step();
|
||||||
|
printf("---[ peer ]----------------------------------\n");
|
||||||
|
res_p = eap_example_peer_step();
|
||||||
|
} while (res_s || res_p);
|
||||||
|
|
||||||
|
eap_example_peer_deinit();
|
||||||
|
eap_example_server_deinit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
270
eap_example/eap_example_peer.c
Normal file
270
eap_example/eap_example_peer.c
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
* Example application showing how EAP peer code from wpa_supplicant can be
|
||||||
|
* used as a library.
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "eap_peer/eap.h"
|
||||||
|
#include "eap_peer/eap_config.h"
|
||||||
|
#include "wpabuf.h"
|
||||||
|
|
||||||
|
void eap_example_server_rx(const u8 *data, size_t data_len);
|
||||||
|
|
||||||
|
|
||||||
|
struct eap_peer_ctx {
|
||||||
|
Boolean eapSuccess;
|
||||||
|
Boolean eapRestart;
|
||||||
|
Boolean eapFail;
|
||||||
|
Boolean eapResp;
|
||||||
|
Boolean eapNoResp;
|
||||||
|
Boolean eapReq;
|
||||||
|
Boolean portEnabled;
|
||||||
|
Boolean altAccept; /* for EAP */
|
||||||
|
Boolean altReject; /* for EAP */
|
||||||
|
|
||||||
|
struct wpabuf *eapReqData; /* for EAP */
|
||||||
|
|
||||||
|
unsigned int idleWhile; /* for EAP state machine */
|
||||||
|
|
||||||
|
struct eap_peer_config eap_config;
|
||||||
|
struct eap_sm *eap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct eap_peer_ctx eap_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
static struct eap_peer_config * peer_get_config(void *ctx)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
return &peer->eap_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
if (peer == NULL)
|
||||||
|
return FALSE;
|
||||||
|
switch (variable) {
|
||||||
|
case EAPOL_eapSuccess:
|
||||||
|
return peer->eapSuccess;
|
||||||
|
case EAPOL_eapRestart:
|
||||||
|
return peer->eapRestart;
|
||||||
|
case EAPOL_eapFail:
|
||||||
|
return peer->eapFail;
|
||||||
|
case EAPOL_eapResp:
|
||||||
|
return peer->eapResp;
|
||||||
|
case EAPOL_eapNoResp:
|
||||||
|
return peer->eapNoResp;
|
||||||
|
case EAPOL_eapReq:
|
||||||
|
return peer->eapReq;
|
||||||
|
case EAPOL_portEnabled:
|
||||||
|
return peer->portEnabled;
|
||||||
|
case EAPOL_altAccept:
|
||||||
|
return peer->altAccept;
|
||||||
|
case EAPOL_altReject:
|
||||||
|
return peer->altReject;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
|
||||||
|
Boolean value)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
if (peer == NULL)
|
||||||
|
return;
|
||||||
|
switch (variable) {
|
||||||
|
case EAPOL_eapSuccess:
|
||||||
|
peer->eapSuccess = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_eapRestart:
|
||||||
|
peer->eapRestart = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_eapFail:
|
||||||
|
peer->eapFail = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_eapResp:
|
||||||
|
peer->eapResp = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_eapNoResp:
|
||||||
|
peer->eapNoResp = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_eapReq:
|
||||||
|
peer->eapReq = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_portEnabled:
|
||||||
|
peer->portEnabled = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_altAccept:
|
||||||
|
peer->altAccept = value;
|
||||||
|
break;
|
||||||
|
case EAPOL_altReject:
|
||||||
|
peer->altReject = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
if (peer == NULL)
|
||||||
|
return 0;
|
||||||
|
switch (variable) {
|
||||||
|
case EAPOL_idleWhile:
|
||||||
|
return peer->idleWhile;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void peer_set_int(void *ctx, enum eapol_int_var variable,
|
||||||
|
unsigned int value)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
if (peer == NULL)
|
||||||
|
return;
|
||||||
|
switch (variable) {
|
||||||
|
case EAPOL_idleWhile:
|
||||||
|
peer->idleWhile = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct wpabuf * peer_get_eapReqData(void *ctx)
|
||||||
|
{
|
||||||
|
struct eap_peer_ctx *peer = ctx;
|
||||||
|
if (peer == NULL || peer->eapReqData == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return peer->eapReqData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
|
||||||
|
{
|
||||||
|
printf("TODO: %s\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct wpa_config_blob *
|
||||||
|
peer_get_config_blob(void *ctx, const char *name)
|
||||||
|
{
|
||||||
|
printf("TODO: %s\n", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void peer_notify_pending(void *ctx)
|
||||||
|
{
|
||||||
|
printf("TODO: %s\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct eapol_callbacks eap_cb;
|
||||||
|
static struct eap_config eap_conf;
|
||||||
|
|
||||||
|
int eap_example_peer_init(void)
|
||||||
|
{
|
||||||
|
if (eap_peer_register_methods() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||||
|
|
||||||
|
eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
|
||||||
|
eap_ctx.eap_config.identity_len = 4;
|
||||||
|
eap_ctx.eap_config.password = (u8 *) os_strdup("password");
|
||||||
|
eap_ctx.eap_config.password_len = 8;
|
||||||
|
eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem");
|
||||||
|
eap_ctx.eap_config.fragment_size = 1398;
|
||||||
|
|
||||||
|
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||||
|
eap_cb.get_config = peer_get_config;
|
||||||
|
eap_cb.get_bool = peer_get_bool;
|
||||||
|
eap_cb.set_bool = peer_set_bool;
|
||||||
|
eap_cb.get_int = peer_get_int;
|
||||||
|
eap_cb.set_int = peer_set_int;
|
||||||
|
eap_cb.get_eapReqData = peer_get_eapReqData;
|
||||||
|
eap_cb.set_config_blob = peer_set_config_blob;
|
||||||
|
eap_cb.get_config_blob = peer_get_config_blob;
|
||||||
|
eap_cb.notify_pending = peer_notify_pending;
|
||||||
|
|
||||||
|
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||||
|
eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
|
||||||
|
if (eap_ctx.eap == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Enable "port" to allow authentication */
|
||||||
|
eap_ctx.portEnabled = TRUE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eap_example_peer_deinit(void)
|
||||||
|
{
|
||||||
|
eap_peer_sm_deinit(eap_ctx.eap);
|
||||||
|
eap_peer_unregister_methods();
|
||||||
|
wpabuf_free(eap_ctx.eapReqData);
|
||||||
|
os_free(eap_ctx.eap_config.identity);
|
||||||
|
os_free(eap_ctx.eap_config.password);
|
||||||
|
os_free(eap_ctx.eap_config.ca_cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int eap_example_peer_step(void)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
res = eap_peer_sm_step(eap_ctx.eap);
|
||||||
|
|
||||||
|
if (eap_ctx.eapResp) {
|
||||||
|
struct wpabuf *resp;
|
||||||
|
printf("==> Response\n");
|
||||||
|
eap_ctx.eapResp = FALSE;
|
||||||
|
resp = eap_get_eapRespData(eap_ctx.eap);
|
||||||
|
if (resp) {
|
||||||
|
/* Send EAP response to the server */
|
||||||
|
eap_example_server_rx(wpabuf_head(resp),
|
||||||
|
wpabuf_len(resp));
|
||||||
|
wpabuf_free(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eap_ctx.eapSuccess) {
|
||||||
|
res = 0;
|
||||||
|
if (eap_key_available(eap_ctx.eap)) {
|
||||||
|
const u8 *key;
|
||||||
|
size_t key_len;
|
||||||
|
key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||||
|
key, key_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eap_example_peer_rx(const u8 *data, size_t data_len)
|
||||||
|
{
|
||||||
|
/* Make received EAP message available to the EAP library */
|
||||||
|
eap_ctx.eapReq = TRUE;
|
||||||
|
wpabuf_free(eap_ctx.eapReqData);
|
||||||
|
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
|
||||||
|
}
|
192
eap_example/eap_example_server.c
Normal file
192
eap_example/eap_example_server.c
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* Example application showing how EAP server code from hostapd can be used as
|
||||||
|
* a library.
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "eap_server/eap.h"
|
||||||
|
#include "tls.h"
|
||||||
|
#include "wpabuf.h"
|
||||||
|
|
||||||
|
void eap_example_peer_rx(const u8 *data, size_t data_len);
|
||||||
|
|
||||||
|
|
||||||
|
struct eap_server_ctx {
|
||||||
|
struct eap_eapol_interface *eap_if;
|
||||||
|
struct eap_sm *eap;
|
||||||
|
void *tls_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct eap_server_ctx eap_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
static int server_get_eap_user(void *ctx, const u8 *identity,
|
||||||
|
size_t identity_len, int phase2,
|
||||||
|
struct eap_user *user)
|
||||||
|
{
|
||||||
|
os_memset(user, 0, sizeof(*user));
|
||||||
|
|
||||||
|
if (!phase2) {
|
||||||
|
/* Only allow EAP-PEAP as the Phase 1 method */
|
||||||
|
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||||
|
user->methods[0].method = EAP_TYPE_PEAP;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identity_len != 4 || identity == NULL ||
|
||||||
|
os_memcmp(identity, "user", 4) != 0) {
|
||||||
|
printf("Unknown user\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only allow EAP-MSCHAPv2 as the Phase 2 method */
|
||||||
|
user->methods[0].vendor = EAP_VENDOR_IETF;
|
||||||
|
user->methods[0].method = EAP_TYPE_MSCHAPV2;
|
||||||
|
user->password = (u8 *) os_strdup("password");
|
||||||
|
user->password_len = 8;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
|
||||||
|
{
|
||||||
|
*len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct eapol_callbacks eap_cb;
|
||||||
|
static struct eap_config eap_conf;
|
||||||
|
|
||||||
|
static int eap_example_server_init_tls(void)
|
||||||
|
{
|
||||||
|
struct tls_config tconf;
|
||||||
|
struct tls_connection_params tparams;
|
||||||
|
|
||||||
|
os_memset(&tconf, 0, sizeof(tconf));
|
||||||
|
eap_ctx.tls_ctx = tls_init(&tconf);
|
||||||
|
if (eap_ctx.tls_ctx == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_memset(&tparams, 0, sizeof(tparams));
|
||||||
|
tparams.ca_cert = "ca.pem";
|
||||||
|
tparams.client_cert = "server.pem";
|
||||||
|
tparams.private_key = "server.key";
|
||||||
|
tparams.private_key_passwd = "whatever";
|
||||||
|
|
||||||
|
if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
|
||||||
|
printf("Failed to set TLS parameters\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tls_global_set_verify(eap_ctx.tls_ctx, 0)) {
|
||||||
|
printf("Failed to set check_crl\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int eap_example_server_init(void)
|
||||||
|
{
|
||||||
|
if (eap_server_register_methods() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_memset(&eap_ctx, 0, sizeof(eap_ctx));
|
||||||
|
|
||||||
|
if (eap_example_server_init_tls() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
os_memset(&eap_cb, 0, sizeof(eap_cb));
|
||||||
|
eap_cb.get_eap_user = server_get_eap_user;
|
||||||
|
eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
|
||||||
|
|
||||||
|
os_memset(&eap_conf, 0, sizeof(eap_conf));
|
||||||
|
eap_conf.eap_server = 1;
|
||||||
|
eap_conf.ssl_ctx = eap_ctx.tls_ctx;
|
||||||
|
|
||||||
|
eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf);
|
||||||
|
if (eap_ctx.eap == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
|
||||||
|
|
||||||
|
/* Enable "port" and request EAP to start authentication. */
|
||||||
|
eap_ctx.eap_if->portEnabled = TRUE;
|
||||||
|
eap_ctx.eap_if->eapRestart = TRUE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eap_example_server_deinit(void)
|
||||||
|
{
|
||||||
|
eap_server_sm_deinit(eap_ctx.eap);
|
||||||
|
eap_server_unregister_methods();
|
||||||
|
tls_deinit(eap_ctx.tls_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int eap_example_server_step(void)
|
||||||
|
{
|
||||||
|
int res, process = 0;
|
||||||
|
|
||||||
|
res = eap_server_sm_step(eap_ctx.eap);
|
||||||
|
|
||||||
|
if (eap_ctx.eap_if->eapReq) {
|
||||||
|
printf("==> Request\n");
|
||||||
|
process = 1;
|
||||||
|
eap_ctx.eap_if->eapReq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eap_ctx.eap_if->eapSuccess) {
|
||||||
|
printf("==> Success\n");
|
||||||
|
process = 1;
|
||||||
|
res = 0;
|
||||||
|
eap_ctx.eap_if->eapSuccess = 0;
|
||||||
|
|
||||||
|
if (eap_ctx.eap_if->eapKeyAvailable) {
|
||||||
|
wpa_hexdump(MSG_DEBUG, "EAP keying material",
|
||||||
|
eap_ctx.eap_if->eapKeyData,
|
||||||
|
eap_ctx.eap_if->eapKeyDataLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eap_ctx.eap_if->eapFail) {
|
||||||
|
printf("==> Fail\n");
|
||||||
|
process = 1;
|
||||||
|
eap_ctx.eap_if->eapFail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process && eap_ctx.eap_if->eapReqData) {
|
||||||
|
/* Send EAP response to the server */
|
||||||
|
eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
|
||||||
|
wpabuf_len(eap_ctx.eap_if->eapReqData));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void eap_example_server_rx(const u8 *data, size_t data_len)
|
||||||
|
{
|
||||||
|
/* Make received EAP message available to the EAP library */
|
||||||
|
wpabuf_free(eap_ctx.eap_if->eapRespData);
|
||||||
|
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
|
||||||
|
if (eap_ctx.eap_if->eapRespData)
|
||||||
|
eap_ctx.eap_if->eapResp = TRUE;
|
||||||
|
}
|
BIN
eap_example/server.key
Normal file
BIN
eap_example/server.key
Normal file
Binary file not shown.
18
eap_example/server.pem
Normal file
18
eap_example/server.pem
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC0zCCAjygAwIBAgIJAIb4NS4TdLXVMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
|
||||||
|
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
|
||||||
|
A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
|
||||||
|
MTIwOTAzMTUwOFoXDTE3MTIwNjAzMTUwOFoweTELMAkGA1UEBhMCVVMxEzARBgNV
|
||||||
|
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDjAMBgNVBAoT
|
||||||
|
BXcxLmZpMRAwDgYDVQQDEwdUZXN0IEFTMRswGQYJKoZIhvcNAQkBFgx0ZXN0YXNA
|
||||||
|
dzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOhi4M+aMRa778CPRFV
|
||||||
|
ZNJvTuxfp0CQ+etNpSNkAbkCGNGolbPMPnSQWZUqL5HsaBLm2UbMtS2iR3CO5JQC
|
||||||
|
bPy0xfAjCZV5LQeW4UNVKL3hdtVFzMT6fKgOKCDVEbLLWZze3lEbzhu81q2r3w5x
|
||||||
|
4lqDieCHwvwjiTWpMtEyXIEnAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
|
||||||
|
QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRb
|
||||||
|
xGTC3mPimgyGb5vYLLV5wyc9ITAfBgNVHSMEGDAWgBSoSbkiyeiYXAf3UYAfI9If
|
||||||
|
ZjpaSjANBgkqhkiG9w0BAQUFAAOBgQA9wVGtroz/rsx1EeALJejW01SAr4kpTxoS
|
||||||
|
WP6zuWFb+J/lJd7DeVM6/QBYAwZb0fB6nwSpJJCj6XDRZtN/yLeaTd/rCZrfom4Z
|
||||||
|
8gbkWMTXDn2Cea2VnCe5W0gK+4dIj5DD5CpPvgt4lYqlwN0WAih6twd7Q4x/tiiJ
|
||||||
|
ejNQzlTHOg==
|
||||||
|
-----END CERTIFICATE-----
|
7
hostapd/.gitignore
vendored
Normal file
7
hostapd/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
*.d
|
||||||
|
.config
|
||||||
|
driver_conf.c
|
||||||
|
hostapd
|
||||||
|
hostapd_cli
|
||||||
|
hlr_auc_gw
|
||||||
|
nt_password_hash
|
477
hostapd/ChangeLog
Normal file
477
hostapd/ChangeLog
Normal file
|
@ -0,0 +1,477 @@
|
||||||
|
ChangeLog for hostapd
|
||||||
|
|
||||||
|
2008-02-22 - v0.6.3
|
||||||
|
* fixed Reassociation Response callback processing when using internal
|
||||||
|
MLME (driver_{hostap,nl80211,test}.c)
|
||||||
|
* updated FT support to use the latest draft, IEEE 802.11r/D9.0
|
||||||
|
* copy optional Proxy-State attributes into RADIUS response when acting
|
||||||
|
as a RADIUS authentication server
|
||||||
|
* fixed EAPOL state machine to handle a case in which no response is
|
||||||
|
received from the RADIUS authentication server; previous version
|
||||||
|
could have triggered a crash in some cases after a timeout
|
||||||
|
* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
|
||||||
|
be used
|
||||||
|
* added a workaround for EAP-SIM/AKA peers that include incorrect null
|
||||||
|
termination in the username
|
||||||
|
* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
|
||||||
|
attribute in notification messages only when using fast
|
||||||
|
reauthentication
|
||||||
|
* fixed EAP-SIM Start response processing for fast reauthentication
|
||||||
|
case
|
||||||
|
* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
|
||||||
|
phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
|
||||||
|
|
||||||
|
2008-01-01 - v0.6.2
|
||||||
|
* fixed EAP-SIM and EAP-AKA message parser to validate attribute
|
||||||
|
lengths properly to avoid potential crash caused by invalid messages
|
||||||
|
* added data structure for storing allocated buffers (struct wpabuf);
|
||||||
|
this does not affect hostapd usage, but many of the APIs changed
|
||||||
|
and various interfaces (e.g., EAP) is not compatible with old
|
||||||
|
versions
|
||||||
|
* added support for protecting EAP-AKA/Identity messages with
|
||||||
|
AT_CHECKCODE (optional feature in RFC 4187)
|
||||||
|
* added support for protected result indication with AT_RESULT_IND for
|
||||||
|
EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
|
||||||
|
* added support for configuring EAP-TTLS phase 2 non-EAP methods in
|
||||||
|
EAP server configuration; previously all four were enabled for every
|
||||||
|
phase 2 user, now all four are disabled by default and need to be
|
||||||
|
enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
|
||||||
|
TTLS-MSCHAPV2
|
||||||
|
* removed old debug printing mechanism and the related 'debug'
|
||||||
|
parameter in the configuration file; debug verbosity is now set with
|
||||||
|
-d (or -dd) command line arguments
|
||||||
|
* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
|
||||||
|
only shared key/password authentication is supported in this version
|
||||||
|
|
||||||
|
2007-11-24 - v0.6.1
|
||||||
|
* added experimental, integrated TLSv1 server implementation with the
|
||||||
|
needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
|
||||||
|
setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
|
||||||
|
.config); this can be useful, e.g., if the target system does not
|
||||||
|
have a suitable TLS library and a minimal code size is required
|
||||||
|
* added support for EAP-FAST server method to the integrated EAP
|
||||||
|
server
|
||||||
|
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||||
|
draft (draft-ietf-emu-eap-gpsk-07.txt)
|
||||||
|
* added a new configuration parameter, rsn_pairwise, to allow different
|
||||||
|
pairwise cipher suites to be enabled for WPA and RSN/WPA2
|
||||||
|
(note: if wpa_pairwise differs from rsn_pairwise, the driver will
|
||||||
|
either need to support this or will have to use the WPA/RSN IEs from
|
||||||
|
hostapd; currently, the included madwifi and bsd driver interfaces do
|
||||||
|
not have support for this)
|
||||||
|
* updated FT support to use the latest draft, IEEE 802.11r/D8.0
|
||||||
|
|
||||||
|
2007-05-28 - v0.6.0
|
||||||
|
* added experimental IEEE 802.11r/D6.0 support
|
||||||
|
* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
|
||||||
|
* updated EAP-PSK to use the IANA-allocated EAP type 47
|
||||||
|
* fixed EAP-PSK bit ordering of the Flags field
|
||||||
|
* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
|
||||||
|
by reading wpa_psk_file [Bug 181]
|
||||||
|
* fixed EAP-TTLS AVP parser processing for too short AVP lengths
|
||||||
|
* fixed IPv6 connection to RADIUS accounting server
|
||||||
|
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||||
|
draft (draft-ietf-emu-eap-gpsk-04.txt)
|
||||||
|
* hlr_auc_gw: read GSM triplet file into memory and rotate through the
|
||||||
|
entries instead of only using the same three triplets every time
|
||||||
|
(this does not work properly with tests using multiple clients, but
|
||||||
|
provides bit better triplet data for testing a single client; anyway,
|
||||||
|
if a better quality triplets are needed, GSM-Milenage should be used
|
||||||
|
instead of hardcoded triplet file)
|
||||||
|
* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
|
||||||
|
in Success Request [Bug 203]
|
||||||
|
* added support for sending EAP-AKA Notifications in error cases
|
||||||
|
* updated to use IEEE 802.11w/D2.0 for management frame protection
|
||||||
|
(still experimental)
|
||||||
|
* RADIUS server: added support for processing duplicate messages
|
||||||
|
(retransmissions from RADIUS client) by replying with the previous
|
||||||
|
reply
|
||||||
|
|
||||||
|
2006-11-24 - v0.5.6
|
||||||
|
* added support for configuring and controlling multiple BSSes per
|
||||||
|
radio interface (bss=<ifname> in hostapd.conf); this is only
|
||||||
|
available with Devicescape and test driver interfaces
|
||||||
|
* fixed PMKSA cache update in the end of successful RSN
|
||||||
|
pre-authentication
|
||||||
|
* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
|
||||||
|
for each STA based on RADIUS Access-Accept attributes); this requires
|
||||||
|
VLAN support from the kernel driver/802.11 stack and this is
|
||||||
|
currently only available with Devicescape and test driver interfaces
|
||||||
|
* driver_madwifi: fixed configuration of unencrypted modes (plaintext
|
||||||
|
and IEEE 802.1X without WEP)
|
||||||
|
* removed STAKey handshake since PeerKey handshake has replaced it in
|
||||||
|
IEEE 802.11ma and there are no known deployments of STAKey
|
||||||
|
* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
|
||||||
|
draft (draft-ietf-emu-eap-gpsk-01.txt)
|
||||||
|
* added preliminary implementation of IEEE 802.11w/D1.0 (management
|
||||||
|
frame protection)
|
||||||
|
(Note: this requires driver support to work properly.)
|
||||||
|
(Note2: IEEE 802.11w is an unapproved draft and subject to change.)
|
||||||
|
* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
|
||||||
|
* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
|
||||||
|
parameters from a text file to make it possible to implement proper
|
||||||
|
GSM/UMTS authentication server for multiple SIM/USIM cards using
|
||||||
|
EAP-SIM/EAP-AKA
|
||||||
|
* fixed session timeout processing with drivers that do not use
|
||||||
|
ieee802_11.c (e.g., madwifi)
|
||||||
|
|
||||||
|
2006-08-27 - v0.5.5
|
||||||
|
* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
|
||||||
|
hostapd (e.g., to initialize wired network authentication based on an
|
||||||
|
external signal)
|
||||||
|
* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
|
||||||
|
using WPA2 even if PMKSA caching is not used
|
||||||
|
* added -P<pid file> argument for hostapd to write the current process
|
||||||
|
id into a file
|
||||||
|
* added support for RADIUS Authentication Server MIB (RFC 2619)
|
||||||
|
|
||||||
|
2006-06-20 - v0.5.4
|
||||||
|
* fixed nt_password_hash build [Bug 144]
|
||||||
|
* added PeerKey handshake implementation for IEEE 802.11e
|
||||||
|
direct link setup (DLS) to replace STAKey handshake
|
||||||
|
* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
|
||||||
|
draft-clancy-emu-eap-shared-secret-00.txt)
|
||||||
|
* fixed a segmentation fault when RSN pre-authentication was completed
|
||||||
|
successfully [Bug 152]
|
||||||
|
|
||||||
|
2006-04-27 - v0.5.3
|
||||||
|
* do not build nt_password_hash and hlr_auc_gw by default to avoid
|
||||||
|
requiring a TLS library for a successful build; these programs can be
|
||||||
|
build with 'make nt_password_hash' and 'make hlr_auc_gw'
|
||||||
|
* added a new configuration option, eapol_version, that can be used to
|
||||||
|
set EAPOL version to 1 (default is 2) to work around broken client
|
||||||
|
implementations that drop EAPOL frames which use version number 2
|
||||||
|
[Bug 89]
|
||||||
|
* added support for EAP-SAKE (no EAP method number allocated yet, so
|
||||||
|
this is using the same experimental type 255 as EAP-PSK)
|
||||||
|
* fixed EAP-MSCHAPv2 message length validation
|
||||||
|
|
||||||
|
2006-03-19 - v0.5.2
|
||||||
|
* fixed stdarg use in hostapd_logger(): if both stdout and syslog
|
||||||
|
logging was enabled, hostapd could trigger a segmentation fault in
|
||||||
|
vsyslog on some CPU -- C library combinations
|
||||||
|
* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
|
||||||
|
program to make it easier to use for implementing real SS7 gateway;
|
||||||
|
eap_sim_db is not anymore used as a file name for GSM authentication
|
||||||
|
triplets; instead, it is path to UNIX domain socket that will be used
|
||||||
|
to communicate with the external gateway program (e.g., hlr_auc_gw)
|
||||||
|
* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
|
||||||
|
local information (GSM authentication triplets from a text file and
|
||||||
|
hardcoded AKA authentication data); this can be used to test EAP-SIM
|
||||||
|
and EAP-AKA
|
||||||
|
* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
|
||||||
|
to make it possible to test EAP-AKA with real USIM cards (this is
|
||||||
|
disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
|
||||||
|
to enable this)
|
||||||
|
* driver_madwifi: added support for getting station RSN IE from
|
||||||
|
madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
|
||||||
|
broken with earlier change (r1357) in the driver
|
||||||
|
* changed EAP method registration to use a dynamic list of methods
|
||||||
|
instead of a static list generated at build time
|
||||||
|
* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
|
||||||
|
[Bug 125]
|
||||||
|
* added ap_max_inactivity configuration parameter
|
||||||
|
|
||||||
|
2006-01-29 - v0.5.1
|
||||||
|
* driver_test: added better support for multiple APs and STAs by using
|
||||||
|
a directory with sockets that include MAC address for each device in
|
||||||
|
the name (test_socket=DIR:/tmp/test)
|
||||||
|
* added support for EAP expanded type (vendor specific EAP methods)
|
||||||
|
|
||||||
|
2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
|
||||||
|
* added experimental STAKey handshake implementation for IEEE 802.11e
|
||||||
|
direct link setup (DLS); note: this is disabled by default in both
|
||||||
|
build and runtime configuration (can be enabled with CONFIG_STAKEY=y
|
||||||
|
and stakey=1)
|
||||||
|
* added support for EAP methods to use callbacks to external programs
|
||||||
|
by buffering a pending request and processing it after the EAP method
|
||||||
|
is ready to continue
|
||||||
|
* improved EAP-SIM database interface to allow external request to GSM
|
||||||
|
HLR/AuC without blocking hostapd process
|
||||||
|
* added support for using EAP-SIM pseudonyms and fast re-authentication
|
||||||
|
* added support for EAP-AKA in the integrated EAP authenticator
|
||||||
|
* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
|
||||||
|
user database to allow EAP-SIM/AKA selection without extra roundtrip
|
||||||
|
for EAP-Nak negotiation
|
||||||
|
* added support for storing EAP user password as NtPasswordHash instead
|
||||||
|
of plaintext password when using MSCHAP or MSCHAPv2 for
|
||||||
|
authentication (hash:<16-octet hex value>); added nt_password_hash
|
||||||
|
tool for hashing password to generate NtPasswordHash
|
||||||
|
|
||||||
|
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
|
||||||
|
* driver_wired: fixed EAPOL sending to optionally use PAE group address
|
||||||
|
as the destination instead of supplicant MAC address; this is
|
||||||
|
disabled by default, but should be enabled with use_pae_group_addr=1
|
||||||
|
in configuration file if the wired interface is used by only one
|
||||||
|
device at the time (common switch configuration)
|
||||||
|
* driver_madwifi: configure driver to use TKIP countermeasures in order
|
||||||
|
to get correct behavior (IEEE 802.11 association failing; previously,
|
||||||
|
association succeeded, but hostpad forced disassociation immediately)
|
||||||
|
* driver_madwifi: added support for madwifi-ng
|
||||||
|
|
||||||
|
2005-10-27 - v0.4.6
|
||||||
|
* added support for replacing user identity from EAP with RADIUS
|
||||||
|
User-Name attribute from Access-Accept message, if that is included,
|
||||||
|
for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
|
||||||
|
tunneled identity into accounting messages when the RADIUS server
|
||||||
|
does not support better way of doing this with Class attribute)
|
||||||
|
* driver_madwifi: fixed EAPOL packet receive for configuration where
|
||||||
|
ath# is part of a bridge interface
|
||||||
|
* added a configuration file and log analyzer script for logwatch
|
||||||
|
* fixed EAPOL state machine step function to process all state
|
||||||
|
transitions before processing new events; this resolves a race
|
||||||
|
condition in which EAPOL-Start message could trigger hostapd to send
|
||||||
|
two EAP-Response/Identity frames to the authentication server
|
||||||
|
|
||||||
|
2005-09-25 - v0.4.5
|
||||||
|
* added client CA list to the TLS certificate request in order to make
|
||||||
|
it easier for the client to select which certificate to use
|
||||||
|
* added experimental support for EAP-PSK
|
||||||
|
* added support for WE-19 (hostap, madwifi)
|
||||||
|
|
||||||
|
2005-08-21 - v0.4.4
|
||||||
|
* fixed build without CONFIG_RSN_PREAUTH
|
||||||
|
* fixed FreeBSD build
|
||||||
|
|
||||||
|
2005-06-26 - v0.4.3
|
||||||
|
* fixed PMKSA caching to copy User-Name and Class attributes so that
|
||||||
|
RADIUS accounting gets correct information
|
||||||
|
* start RADIUS accounting only after successful completion of WPA
|
||||||
|
4-Way Handshake if WPA-PSK is used
|
||||||
|
* fixed PMKSA caching for the case where STA (re)associates without
|
||||||
|
first disassociating
|
||||||
|
|
||||||
|
2005-06-12 - v0.4.2
|
||||||
|
* EAP-PAX is now registered as EAP type 46
|
||||||
|
* fixed EAP-PAX MAC calculation
|
||||||
|
* fixed EAP-PAX CK and ICK key derivation
|
||||||
|
* renamed eap_authenticator configuration variable to eap_server to
|
||||||
|
better match with RFC 3748 (EAP) terminology
|
||||||
|
* driver_test: added support for testing hostapd with wpa_supplicant
|
||||||
|
by using test driver interface without any kernel drivers or network
|
||||||
|
cards
|
||||||
|
|
||||||
|
2005-05-22 - v0.4.1
|
||||||
|
* fixed RADIUS server initialization when only auth or acct server
|
||||||
|
is configured and the other one is left empty
|
||||||
|
* driver_madwifi: added support for RADIUS accounting
|
||||||
|
* driver_madwifi: added preliminary support for compiling against 'BSD'
|
||||||
|
branch of madwifi CVS tree
|
||||||
|
* driver_madwifi: fixed pairwise key removal to allow WPA reauth
|
||||||
|
without disassociation
|
||||||
|
* added support for reading additional certificates from PKCS#12 files
|
||||||
|
and adding them to the certificate chain
|
||||||
|
* fixed RADIUS Class attribute processing to only use Access-Accept
|
||||||
|
packets to update Class; previously, other RADIUS authentication
|
||||||
|
packets could have cleared Class attribute
|
||||||
|
* added support for more than one Class attribute in RADIUS packets
|
||||||
|
* added support for verifying certificate revocation list (CRL) when
|
||||||
|
using integrated EAP authenticator for EAP-TLS; new hostapd.conf
|
||||||
|
options 'check_crl'; CRL must be included in the ca_cert file for now
|
||||||
|
|
||||||
|
2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
|
||||||
|
* added support for including network information into
|
||||||
|
EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
|
||||||
|
(e.g., to implement draft-adrange-eap-network-discovery-07.txt)
|
||||||
|
* fixed a bug which caused some RSN pre-authentication cases to use
|
||||||
|
freed memory and potentially crash hostapd
|
||||||
|
* fixed private key loading for cases where passphrase is not set
|
||||||
|
* added support for sending TLS alerts and aborting authentication
|
||||||
|
when receiving a TLS alert
|
||||||
|
* fixed WPA2 to add PMKSA cache entry when using integrated EAP
|
||||||
|
authenticator
|
||||||
|
* fixed PMKSA caching (EAP authentication was not skipped correctly
|
||||||
|
with the new state machine changes from IEEE 802.1X draft)
|
||||||
|
* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
|
||||||
|
and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
|
||||||
|
to be added to .config to include IPv6 support); for RADIUS server,
|
||||||
|
radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
|
||||||
|
in RADIUS clients file can then use IPv6 format
|
||||||
|
* added experimental support for EAP-PAX
|
||||||
|
* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
|
||||||
|
the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
|
||||||
|
|
||||||
|
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
|
||||||
|
|
||||||
|
2005-01-23 - v0.3.5
|
||||||
|
* added support for configuring a forced PEAP version based on the
|
||||||
|
Phase 1 identity
|
||||||
|
* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
|
||||||
|
to terminate authentication
|
||||||
|
* fixed EAP identifier duplicate processing with the new IEEE 802.1X
|
||||||
|
draft
|
||||||
|
* clear accounting data in the driver when starting a new accounting
|
||||||
|
session
|
||||||
|
* driver_madwifi: filter wireless events based on ifindex to allow more
|
||||||
|
than one network interface to be used
|
||||||
|
* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
|
||||||
|
setting if the packet does not pass MIC verification (e.g., due to
|
||||||
|
incorrect PSK); previously, message 1/4 was not tried again if an
|
||||||
|
invalid message 2/4 was received
|
||||||
|
* fixed reconfiguration of RADIUS client retransmission timer when
|
||||||
|
adding a new message to the pending list; previously, timer was not
|
||||||
|
updated at this point and if there was a pending message with long
|
||||||
|
time for the next retry, the new message needed to wait that long for
|
||||||
|
its first retry, too
|
||||||
|
|
||||||
|
2005-01-09 - v0.3.4
|
||||||
|
* added support for configuring multiple allowed EAP types for Phase 2
|
||||||
|
authentication (EAP-PEAP, EAP-TTLS)
|
||||||
|
* fixed EAPOL-Start processing to trigger WPA reauthentication
|
||||||
|
(previously, only EAPOL authentication was done)
|
||||||
|
|
||||||
|
2005-01-02 - v0.3.3
|
||||||
|
* added support for EAP-PEAP in the integrated EAP authenticator
|
||||||
|
* added support for EAP-GTC in the integrated EAP authenticator
|
||||||
|
* added support for configuring list of EAP methods for Phase 1 so that
|
||||||
|
the integrated EAP authenticator can, e.g., use the wildcard entry
|
||||||
|
for EAP-TLS and EAP-PEAP
|
||||||
|
* added support for EAP-TTLS in the integrated EAP authenticator
|
||||||
|
* added support for EAP-SIM in the integrated EAP authenticator
|
||||||
|
* added support for using hostapd as a RADIUS authentication server
|
||||||
|
with the integrated EAP authenticator taking care of EAP
|
||||||
|
authentication (new hostapd.conf options: radius_server_clients and
|
||||||
|
radius_server_auth_port); this is not included in default build; use
|
||||||
|
CONFIG_RADIUS_SERVER=y in .config to include
|
||||||
|
|
||||||
|
2004-12-19 - v0.3.2
|
||||||
|
* removed 'daemonize' configuration file option since it has not really
|
||||||
|
been used at all for more than year
|
||||||
|
* driver_madwifi: fixed group key setup and added get_ssid method
|
||||||
|
* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
|
||||||
|
|
||||||
|
2004-12-12 - v0.3.1
|
||||||
|
* added support for integrated EAP-TLS authentication (new hostapd.conf
|
||||||
|
variables: ca_cert, server_cert, private_key, private_key_passwd);
|
||||||
|
this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
|
||||||
|
external RADIUS server
|
||||||
|
* added support for reading PKCS#12 (PFX) files (as a replacement for
|
||||||
|
PEM/DER) to get certificate and private key (CONFIG_PKCS12)
|
||||||
|
|
||||||
|
2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
|
||||||
|
* added support for Acct-{Input,Output}-Gigawords
|
||||||
|
* added support for Event-Timestamp (in RADIUS Accounting-Requests)
|
||||||
|
* added support for RADIUS Authentication Client MIB (RFC2618)
|
||||||
|
* added support for RADIUS Accounting Client MIB (RFC2620)
|
||||||
|
* made EAP re-authentication period configurable (eap_reauth_period)
|
||||||
|
* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
|
||||||
|
* fixed EAPOL state machine to stop if STA is removed during
|
||||||
|
eapol_sm_step(); this fixes at least one segfault triggering bug with
|
||||||
|
IEEE 802.11i pre-authentication
|
||||||
|
* added support for multiple WPA pre-shared keys (e.g., one for each
|
||||||
|
client MAC address or keys shared by a group of clients);
|
||||||
|
new hostapd.conf field wpa_psk_file for setting path to a text file
|
||||||
|
containing PSKs, see hostapd.wpa_psk for an example
|
||||||
|
* added support for multiple driver interfaces to allow hostapd to be
|
||||||
|
used with other drivers
|
||||||
|
* added wired authenticator driver interface (driver=wired in
|
||||||
|
hostapd.conf, see wired.conf for example configuration)
|
||||||
|
* added madwifi driver interface (driver=madwifi in hostapd.conf, see
|
||||||
|
madwifi.conf for example configuration; Note: include files from
|
||||||
|
madwifi project is needed for building and a configuration file,
|
||||||
|
.config, needs to be created in hostapd directory with
|
||||||
|
CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
|
||||||
|
build)
|
||||||
|
* fixed an alignment issue that could cause SHA-1 to fail on some
|
||||||
|
platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
|
||||||
|
align variables)
|
||||||
|
* fixed RADIUS reconnection after an error in sending interim
|
||||||
|
accounting packets
|
||||||
|
* added hostapd control interface for external programs and an example
|
||||||
|
CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
|
||||||
|
* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
|
||||||
|
'hostapd_cli sta <addr>')
|
||||||
|
* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
|
||||||
|
* added support for strict GTK rekeying (wpa_strict_rekey in
|
||||||
|
hostapd.conf)
|
||||||
|
* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
|
||||||
|
(instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
|
||||||
|
IEEE 802.11F-2003)
|
||||||
|
* added Prism54 driver interface (driver=prism54 in hostapd.conf;
|
||||||
|
note: .config needs to be created in hostapd directory with
|
||||||
|
CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
|
||||||
|
build)
|
||||||
|
* dual-licensed hostapd (GPLv2 and BSD licenses)
|
||||||
|
* fixed RADIUS accounting to generate a new session id for cases where
|
||||||
|
a station reassociates without first being complete deauthenticated
|
||||||
|
* fixed STA disassociation handler to mark next timeout state to
|
||||||
|
deauthenticate the station, i.e., skip long wait for inactivity poll
|
||||||
|
and extra disassociation, if the STA disassociates without
|
||||||
|
deauthenticating
|
||||||
|
* added integrated EAP authenticator that can be used instead of
|
||||||
|
external RADIUS authentication server; currently, only EAP-MD5 is
|
||||||
|
supported, so this cannot yet be used for key distribution; the EAP
|
||||||
|
method interface is generic, though, so adding new EAP methods should
|
||||||
|
be straightforward; new hostapd.conf variables: 'eap_authenticator'
|
||||||
|
and 'eap_user_file'; this obsoletes "minimal authentication server"
|
||||||
|
('minimal_eap' in hostapd.conf) which is now removed
|
||||||
|
* added support for FreeBSD and driver interface for the BSD net80211
|
||||||
|
layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
|
||||||
|
.config); please note that some of the required kernel mods have not
|
||||||
|
yet been committed
|
||||||
|
|
||||||
|
2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
|
||||||
|
* fixed some accounting cases where Accounting-Start was sent when
|
||||||
|
IEEE 802.1X port was being deauthorized
|
||||||
|
|
||||||
|
2004-06-20 - v0.2.3
|
||||||
|
* modified RADIUS client to re-connect the socket in case of certain
|
||||||
|
error codes that are generated when a network interface state is
|
||||||
|
changes (e.g., when IP address changes or the interface is set UP)
|
||||||
|
* fixed couple of cases where EAPOL state for a station was freed
|
||||||
|
twice causing a segfault for hostapd
|
||||||
|
* fixed couple of bugs in processing WPA deauthentication (freed data
|
||||||
|
was used)
|
||||||
|
|
||||||
|
2004-05-31 - v0.2.2
|
||||||
|
* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
|
||||||
|
* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
|
||||||
|
cases where STAs dropped multicast frames as replay attacks
|
||||||
|
* added support for copying RADIUS Attribute 'Class' from
|
||||||
|
authentication messages into accounting messages
|
||||||
|
* send canned EAP failure if RADIUS server sends Access-Reject without
|
||||||
|
EAP message (previously, Supplicant was not notified in this case)
|
||||||
|
* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
|
||||||
|
not start EAPOL state machines if the STA selected to use WPA-PSK)
|
||||||
|
|
||||||
|
2004-05-06 - v0.2.1
|
||||||
|
* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
|
||||||
|
- based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
|
||||||
|
(i.e., IEEE 802.11i/D3.0)
|
||||||
|
- supports WPA-only, RSN-only, and mixed WPA/RSN mode
|
||||||
|
- both WPA-PSK and WPA-RADIUS/EAP are supported
|
||||||
|
- PMKSA caching and pre-authentication
|
||||||
|
- new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
|
||||||
|
wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
|
||||||
|
rsn_preauth, rsn_preauth_interfaces
|
||||||
|
* fixed interim accounting to remove any pending accounting messages
|
||||||
|
to the STA before sending a new one
|
||||||
|
|
||||||
|
2004-02-15 - v0.2.0
|
||||||
|
* added support for Acct-Interim-Interval:
|
||||||
|
- draft-ietf-radius-acct-interim-01.txt
|
||||||
|
- use Acct-Interim-Interval attribute from Access-Accept if local
|
||||||
|
'radius_acct_interim_interval' is not set
|
||||||
|
- allow different update intervals for each STA
|
||||||
|
* fixed event loop to call signal handlers only after returning from
|
||||||
|
the real signal handler
|
||||||
|
* reset sta->timeout_next after successful association to make sure
|
||||||
|
that the previously registered inactivity timer will not remove the
|
||||||
|
STA immediately (e.g., if STA deauthenticates and re-associates
|
||||||
|
before the timer is triggered).
|
||||||
|
* added new hostapd.conf variable, nas_identifier, that can be used to
|
||||||
|
add an optional RADIUS Attribute, NAS-Identifier, into authentication
|
||||||
|
and accounting messages
|
||||||
|
* added support for Accounting-On and Accounting-Off messages
|
||||||
|
* fixed accounting session handling to send Accounting-Start only once
|
||||||
|
per session and not to send Accounting-Stop if the session was not
|
||||||
|
initialized properly
|
||||||
|
* fixed Accounting-Stop statistics in cases where the message was
|
||||||
|
previously sent after the kernel entry for the STA (and/or IEEE
|
||||||
|
802.1X data) was removed
|
||||||
|
|
||||||
|
|
||||||
|
Note:
|
||||||
|
|
||||||
|
Older changes up to and including v0.1.0 are included in the ChangeLog
|
||||||
|
of the Host AP driver.
|
534
hostapd/Makefile
Normal file
534
hostapd/Makefile
Normal file
|
@ -0,0 +1,534 @@
|
||||||
|
ifndef CC
|
||||||
|
CC=gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CFLAGS
|
||||||
|
CFLAGS = -MMD -O2 -Wall -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
|
||||||
|
# a file (undefine it, if you want to save in binary size)
|
||||||
|
CFLAGS += -DHOSTAPD_DUMP_STATE
|
||||||
|
|
||||||
|
CFLAGS += -I../src
|
||||||
|
CFLAGS += -I../src/crypto
|
||||||
|
CFLAGS += -I../src/utils
|
||||||
|
CFLAGS += -I../src/common
|
||||||
|
|
||||||
|
# Uncomment following line and set the path to your kernel tree include
|
||||||
|
# directory if your C library does not include all header files.
|
||||||
|
# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
|
||||||
|
|
||||||
|
-include .config
|
||||||
|
|
||||||
|
ifndef CONFIG_OS
|
||||||
|
ifdef CONFIG_NATIVE_WINDOWS
|
||||||
|
CONFIG_OS=win32
|
||||||
|
else
|
||||||
|
CONFIG_OS=unix
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_OS), internal)
|
||||||
|
CFLAGS += -DOS_NO_C_LIB_DEFINES
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_NATIVE_WINDOWS
|
||||||
|
CFLAGS += -DCONFIG_NATIVE_WINDOWS
|
||||||
|
LIBS += -lws2_32
|
||||||
|
endif
|
||||||
|
|
||||||
|
OBJS = hostapd.o ieee802_1x.o eapol_sm.o \
|
||||||
|
ieee802_11.o config.o ieee802_11_auth.o accounting.o \
|
||||||
|
sta_info.o wpa.o ctrl_iface.o \
|
||||||
|
drivers.o preauth.o pmksa_cache.o beacon.o \
|
||||||
|
hw_features.o wme.o ap_list.o reconfig.o \
|
||||||
|
mlme.o vlan_init.o ieee802_11h.o wpa_auth_ie.o
|
||||||
|
|
||||||
|
OBJS += ../src/utils/eloop.o
|
||||||
|
OBJS += ../src/utils/common.o
|
||||||
|
OBJS += ../src/utils/wpa_debug.o
|
||||||
|
OBJS += ../src/utils/wpabuf.o
|
||||||
|
OBJS += ../src/utils/os_$(CONFIG_OS).o
|
||||||
|
OBJS += ../src/utils/ip_addr.o
|
||||||
|
|
||||||
|
OBJS += ../src/common/wpa_common.o
|
||||||
|
|
||||||
|
OBJS += ../src/radius/radius.o
|
||||||
|
OBJS += ../src/radius/radius_client.o
|
||||||
|
|
||||||
|
OBJS += ../src/crypto/md5.o
|
||||||
|
OBJS += ../src/crypto/rc4.o
|
||||||
|
OBJS += ../src/crypto/md4.o
|
||||||
|
OBJS += ../src/crypto/sha1.o
|
||||||
|
OBJS += ../src/crypto/des.o
|
||||||
|
OBJS += ../src/crypto/aes_wrap.o
|
||||||
|
OBJS += ../src/crypto/aes.o
|
||||||
|
|
||||||
|
HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
|
||||||
|
|
||||||
|
CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
|
||||||
|
|
||||||
|
ifdef CONFIG_IAPP
|
||||||
|
CFLAGS += -DCONFIG_IAPP
|
||||||
|
OBJS += iapp.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_RSN_PREAUTH
|
||||||
|
CFLAGS += -DCONFIG_RSN_PREAUTH
|
||||||
|
CONFIG_L2_PACKET=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_PEERKEY
|
||||||
|
CFLAGS += -DCONFIG_PEERKEY
|
||||||
|
OBJS += peerkey.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_IEEE80211W
|
||||||
|
CFLAGS += -DCONFIG_IEEE80211W
|
||||||
|
NEED_SHA256=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_IEEE80211R
|
||||||
|
CFLAGS += -DCONFIG_IEEE80211R
|
||||||
|
OBJS += wpa_ft.o
|
||||||
|
NEED_SHA256=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_HOSTAP
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_HOSTAP
|
||||||
|
OBJS += driver_hostap.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_WIRED
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_WIRED
|
||||||
|
OBJS += driver_wired.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_MADWIFI
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_MADWIFI
|
||||||
|
OBJS += driver_madwifi.o
|
||||||
|
CONFIG_L2_PACKET=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_PRISM54
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_PRISM54
|
||||||
|
OBJS += driver_prism54.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_NL80211
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_NL80211
|
||||||
|
OBJS += driver_nl80211.o radiotap.o
|
||||||
|
LIBS += -lnl
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_BSD
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_BSD
|
||||||
|
OBJS += driver_bsd.o
|
||||||
|
CONFIG_L2_PACKET=y
|
||||||
|
CONFIG_DNET_PCAP=y
|
||||||
|
CONFIG_L2_FREEBSD=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_DRIVER_TEST
|
||||||
|
CFLAGS += -DCONFIG_DRIVER_TEST
|
||||||
|
OBJS += driver_test.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_L2_PACKET
|
||||||
|
ifdef CONFIG_DNET_PCAP
|
||||||
|
ifdef CONFIG_L2_FREEBSD
|
||||||
|
LIBS += -lpcap
|
||||||
|
OBJS += ../src/l2_packet/l2_packet_freebsd.o
|
||||||
|
else
|
||||||
|
LIBS += -ldnet -lpcap
|
||||||
|
OBJS += ../src/l2_packet/l2_packet_pcap.o
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
OBJS += ../src/l2_packet/l2_packet_linux.o
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_MD5
|
||||||
|
CFLAGS += -DEAP_MD5
|
||||||
|
OBJS += ../src/eap_server/eap_md5.o
|
||||||
|
CHAP=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_TLS
|
||||||
|
CFLAGS += -DEAP_TLS
|
||||||
|
OBJS += ../src/eap_server/eap_tls.o
|
||||||
|
TLS_FUNCS=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_PEAP
|
||||||
|
CFLAGS += -DEAP_PEAP
|
||||||
|
OBJS += ../src/eap_server/eap_peap.o
|
||||||
|
TLS_FUNCS=y
|
||||||
|
CONFIG_EAP_TLV=y
|
||||||
|
CONFIG_EAP_MSCHAPV2=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_TTLS
|
||||||
|
CFLAGS += -DEAP_TTLS
|
||||||
|
OBJS += ../src/eap_server/eap_ttls.o
|
||||||
|
TLS_FUNCS=y
|
||||||
|
CHAP=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_MSCHAPV2
|
||||||
|
CFLAGS += -DEAP_MSCHAPv2
|
||||||
|
OBJS += ../src/eap_server/eap_mschapv2.o
|
||||||
|
MS_FUNCS=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_GTC
|
||||||
|
CFLAGS += -DEAP_GTC
|
||||||
|
OBJS += ../src/eap_server/eap_gtc.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_SIM
|
||||||
|
CFLAGS += -DEAP_SIM
|
||||||
|
OBJS += ../src/eap_server/eap_sim.o
|
||||||
|
CONFIG_EAP_SIM_COMMON=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_AKA
|
||||||
|
CFLAGS += -DEAP_AKA
|
||||||
|
OBJS += ../src/eap_server/eap_aka.o
|
||||||
|
CONFIG_EAP_SIM_COMMON=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_SIM_COMMON
|
||||||
|
OBJS += ../src/eap_common/eap_sim_common.o
|
||||||
|
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
|
||||||
|
# replaced with another file implementating the interface specified in
|
||||||
|
# eap_sim_db.h.
|
||||||
|
OBJS += ../src/eap_server/eap_sim_db.o
|
||||||
|
NEED_FIPS186_2_PRF=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_PAX
|
||||||
|
CFLAGS += -DEAP_PAX
|
||||||
|
OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_PSK
|
||||||
|
CFLAGS += -DEAP_PSK
|
||||||
|
OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_SAKE
|
||||||
|
CFLAGS += -DEAP_SAKE
|
||||||
|
OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_GPSK
|
||||||
|
CFLAGS += -DEAP_GPSK
|
||||||
|
OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
|
||||||
|
ifdef CONFIG_EAP_GPSK_SHA256
|
||||||
|
CFLAGS += -DEAP_GPSK_SHA256
|
||||||
|
endif
|
||||||
|
NEED_SHA256=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_VENDOR_TEST
|
||||||
|
CFLAGS += -DEAP_VENDOR_TEST
|
||||||
|
OBJS += ../src/eap_server/eap_vendor_test.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_TLV
|
||||||
|
CFLAGS += -DEAP_TLV
|
||||||
|
OBJS += ../src/eap_server/eap_tlv.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_FAST
|
||||||
|
CFLAGS += -DEAP_FAST
|
||||||
|
OBJS += ../src/eap_server/eap_fast.o
|
||||||
|
TLS_FUNCS=y
|
||||||
|
NEED_T_PRF=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP_IKEV2
|
||||||
|
CFLAGS += -DEAP_IKEV2
|
||||||
|
OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o
|
||||||
|
OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
|
||||||
|
NEED_DH_GROUPS=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Basic EAP functionality is needed for EAPOL
|
||||||
|
OBJS += ../src/eap_server/eap.o
|
||||||
|
OBJS += ../src/eap_common/eap_common.o
|
||||||
|
OBJS += ../src/eap_server/eap_methods.o
|
||||||
|
OBJS += ../src/eap_server/eap_identity.o
|
||||||
|
|
||||||
|
ifdef CONFIG_EAP
|
||||||
|
CFLAGS += -DEAP_SERVER
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef CONFIG_TLS
|
||||||
|
CONFIG_TLS=openssl
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_TLS), internal)
|
||||||
|
ifndef CONFIG_CRYPTO
|
||||||
|
CONFIG_CRYPTO=internal
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
|
||||||
|
CFLAGS += -DCONFIG_INTERNAL_X509
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_CRYPTO), internal)
|
||||||
|
CFLAGS += -DCONFIG_INTERNAL_X509
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifdef TLS_FUNCS
|
||||||
|
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
|
||||||
|
CFLAGS += -DEAP_TLS_FUNCS
|
||||||
|
OBJS += ../src/eap_server/eap_tls_common.o
|
||||||
|
ifeq ($(CONFIG_TLS), openssl)
|
||||||
|
OBJS += ../src/crypto/tls_openssl.o
|
||||||
|
LIBS += -lssl -lcrypto
|
||||||
|
LIBS_p += -lcrypto
|
||||||
|
LIBS_h += -lcrypto
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), gnutls)
|
||||||
|
OBJS += ../src/crypto/tls_gnutls.o
|
||||||
|
LIBS += -lgnutls -lgcrypt -lgpg-error
|
||||||
|
LIBS_p += -lgcrypt
|
||||||
|
LIBS_h += -lgcrypt
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_GNUTLS_EXTRA
|
||||||
|
CFLAGS += -DCONFIG_GNUTLS_EXTRA
|
||||||
|
LIBS += -lgnutls-extra
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), internal)
|
||||||
|
OBJS += ../src/crypto/tls_internal.o
|
||||||
|
OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
|
||||||
|
OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o
|
||||||
|
OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
|
||||||
|
OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
|
||||||
|
OBJS_p += ../src/tls/asn1.o
|
||||||
|
OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
|
||||||
|
NEED_BASE64=y
|
||||||
|
CFLAGS += -DCONFIG_TLS_INTERNAL
|
||||||
|
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
|
||||||
|
ifeq ($(CONFIG_CRYPTO), internal)
|
||||||
|
ifdef CONFIG_INTERNAL_LIBTOMMATH
|
||||||
|
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
|
||||||
|
else
|
||||||
|
LIBS += -ltommath
|
||||||
|
LIBS_p += -ltommath
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
|
||||||
|
LIBS += -ltomcrypt -ltfm
|
||||||
|
LIBS_p += -ltomcrypt -ltfm
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
NEED_CRYPTO=y
|
||||||
|
else
|
||||||
|
OBJS += ../src/crypto/tls_none.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_PKCS12
|
||||||
|
CFLAGS += -DPKCS12_FUNCS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef MS_FUNCS
|
||||||
|
OBJS += ../src/crypto/ms_funcs.o
|
||||||
|
NEED_CRYPTO=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CHAP
|
||||||
|
OBJS += ../src/eap_common/chap.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_CRYPTO
|
||||||
|
ifndef TLS_FUNCS
|
||||||
|
ifeq ($(CONFIG_TLS), openssl)
|
||||||
|
LIBS += -lcrypto
|
||||||
|
LIBS_p += -lcrypto
|
||||||
|
LIBS_h += -lcrypto
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), gnutls)
|
||||||
|
LIBS += -lgcrypt
|
||||||
|
LIBS_p += -lgcrypt
|
||||||
|
LIBS_h += -lgcrypt
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), internal)
|
||||||
|
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
|
||||||
|
LIBS += -ltomcrypt -ltfm
|
||||||
|
LIBS_p += -ltomcrypt -ltfm
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), openssl)
|
||||||
|
OBJS += ../src/crypto/crypto_openssl.o
|
||||||
|
OBJS_p += ../src/crypto/crypto_openssl.o
|
||||||
|
HOBJS += ../src/crypto/crypto_openssl.o
|
||||||
|
CONFIG_INTERNAL_SHA256=y
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), gnutls)
|
||||||
|
OBJS += ../src/crypto/crypto_gnutls.o
|
||||||
|
OBJS_p += ../src/crypto/crypto_gnutls.o
|
||||||
|
HOBJS += ../src/crypto/crypto_gnutls.o
|
||||||
|
CONFIG_INTERNAL_SHA256=y
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_TLS), internal)
|
||||||
|
ifeq ($(CONFIG_CRYPTO), libtomcrypt)
|
||||||
|
OBJS += ../src/crypto/crypto_libtomcrypt.o
|
||||||
|
OBJS_p += ../src/crypto/crypto_libtomcrypt.o
|
||||||
|
CONFIG_INTERNAL_SHA256=y
|
||||||
|
endif
|
||||||
|
ifeq ($(CONFIG_CRYPTO), internal)
|
||||||
|
OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
|
||||||
|
OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
|
||||||
|
CFLAGS += -DCONFIG_CRYPTO_INTERNAL
|
||||||
|
CONFIG_INTERNAL_AES=y
|
||||||
|
CONFIG_INTERNAL_DES=y
|
||||||
|
CONFIG_INTERNAL_SHA1=y
|
||||||
|
CONFIG_INTERNAL_MD4=y
|
||||||
|
CONFIG_INTERNAL_MD5=y
|
||||||
|
CONFIG_INTERNAL_SHA256=y
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
CONFIG_INTERNAL_AES=y
|
||||||
|
CONFIG_INTERNAL_SHA1=y
|
||||||
|
CONFIG_INTERNAL_MD5=y
|
||||||
|
CONFIG_INTERNAL_SHA256=y
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_INTERNAL_AES
|
||||||
|
CFLAGS += -DINTERNAL_AES
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_INTERNAL_SHA1
|
||||||
|
CFLAGS += -DINTERNAL_SHA1
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_INTERNAL_SHA256
|
||||||
|
CFLAGS += -DINTERNAL_SHA256
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_INTERNAL_MD5
|
||||||
|
CFLAGS += -DINTERNAL_MD5
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_INTERNAL_MD4
|
||||||
|
CFLAGS += -DINTERNAL_MD4
|
||||||
|
endif
|
||||||
|
ifdef CONFIG_INTERNAL_DES
|
||||||
|
CFLAGS += -DINTERNAL_DES
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_SHA256
|
||||||
|
OBJS += ../src/crypto/sha256.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_DH_GROUPS
|
||||||
|
OBJS += ../src/crypto/dh_groups.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef NEED_FIPS186_2_PRF
|
||||||
|
CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef NEED_T_PRF
|
||||||
|
CFLAGS += -DCONFIG_NO_T_PRF
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_RADIUS_SERVER
|
||||||
|
CFLAGS += -DRADIUS_SERVER
|
||||||
|
OBJS += ../src/radius/radius_server.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_IPV6
|
||||||
|
CFLAGS += -DCONFIG_IPV6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
|
||||||
|
# and vlan interfaces for the vlan feature.
|
||||||
|
CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NEED_BASE64
|
||||||
|
OBJS += ../src/utils/base64.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ALL=hostapd hostapd_cli
|
||||||
|
|
||||||
|
all: verify_config $(ALL)
|
||||||
|
|
||||||
|
verify_config:
|
||||||
|
@if [ ! -r .config ]; then \
|
||||||
|
echo 'Building hostapd requires a configuration file'; \
|
||||||
|
echo '(.config). See README for more instructions. You can'; \
|
||||||
|
echo 'run "cp defconfig .config" to create an example'; \
|
||||||
|
echo 'configuration.'; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
install: all
|
||||||
|
for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
|
||||||
|
|
||||||
|
hostapd: $(OBJS)
|
||||||
|
$(CC) -o hostapd $(OBJS) $(LIBS)
|
||||||
|
|
||||||
|
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
|
||||||
|
hostapd_cli: $(OBJS_c)
|
||||||
|
$(CC) -o hostapd_cli $(OBJS_c)
|
||||||
|
|
||||||
|
NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o
|
||||||
|
NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
|
||||||
|
ifdef TLS_FUNCS
|
||||||
|
LIBS_n += -lcrypto
|
||||||
|
endif
|
||||||
|
|
||||||
|
nt_password_hash: $(NOBJS)
|
||||||
|
$(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
|
||||||
|
|
||||||
|
hlr_auc_gw: $(HOBJS)
|
||||||
|
$(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C ../src clean
|
||||||
|
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
|
||||||
|
rm -f *.d
|
||||||
|
|
||||||
|
%.eps: %.fig
|
||||||
|
fig2dev -L eps $*.fig $*.eps
|
||||||
|
|
||||||
|
%.png: %.fig
|
||||||
|
fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
|
||||||
|
> $*.png
|
||||||
|
|
||||||
|
docs-pics: doc/hostapd.png doc/hostapd.eps
|
||||||
|
|
||||||
|
docs: docs-pics
|
||||||
|
doxygen doc/doxygen.full
|
||||||
|
$(MAKE) -C doc/latex
|
||||||
|
cp doc/latex/refman.pdf hostapd-devel.pdf
|
||||||
|
|
||||||
|
docs-fast: docs-pics
|
||||||
|
doxygen doc/doxygen.fast
|
||||||
|
|
||||||
|
clean-docs:
|
||||||
|
rm -rf doc/latex doc/html
|
||||||
|
rm -f doc/hosta.d{eps,png} hostapd-devel.pdf
|
||||||
|
|
||||||
|
TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c
|
||||||
|
test-milenage: $(TEST_SRC_MILENAGE)
|
||||||
|
$(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
|
||||||
|
-DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \
|
||||||
|
-I../src/crypto -I../src/utils
|
||||||
|
./test-milenage
|
||||||
|
rm test-milenage
|
||||||
|
|
||||||
|
hostapd-sparse: $(OBJS)
|
||||||
|
@echo Sparse run completed
|
||||||
|
|
||||||
|
run-sparse:
|
||||||
|
CC="sparse -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -D__INT_MAX__=2147483647 -D__SHRT_MAX__=32767 -D__LONG_MAX__=2147483647 -D__SCHAR_MAX__=127 -Wbitwise" $(MAKE) hostapd-sparse
|
||||||
|
|
||||||
|
-include $(OBJS:%.o=%.d)
|
386
hostapd/README
Normal file
386
hostapd/README
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||||
|
Authenticator and RADIUS authentication server
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> and contributors
|
||||||
|
All Rights Reserved.
|
||||||
|
|
||||||
|
This program is dual-licensed under both the GPL version 2 and BSD
|
||||||
|
license. Either license may be used at your option.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
GPL v2:
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License version 2 as
|
||||||
|
published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
(this copy of the license is in COPYING file)
|
||||||
|
|
||||||
|
|
||||||
|
Alternatively, this software may be distributed, used, and modified
|
||||||
|
under the terms of BSD license:
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name(s) of the above-listed copyright holder(s) nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
Originally, hostapd was an optional user space component for Host AP
|
||||||
|
driver. It adds more features to the basic IEEE 802.11 management
|
||||||
|
included in the kernel driver: using external RADIUS authentication
|
||||||
|
server for MAC address based access control, IEEE 802.1X Authenticator
|
||||||
|
and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
|
||||||
|
Authenticator and dynamic TKIP/CCMP keying.
|
||||||
|
|
||||||
|
The current version includes support for other drivers, an integrated
|
||||||
|
EAP server (i.e., allow full authentication without requiring
|
||||||
|
an external RADIUS authentication server), and RADIUS authentication
|
||||||
|
server for EAP authentication.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Current hardware/software requirements:
|
||||||
|
- drivers:
|
||||||
|
Host AP driver for Prism2/2.5/3.
|
||||||
|
(http://hostap.epitest.fi/)
|
||||||
|
Please note that station firmware version needs to be 1.7.0 or newer
|
||||||
|
to work in WPA mode.
|
||||||
|
|
||||||
|
madwifi driver for cards based on Atheros chip set (ar521x)
|
||||||
|
(http://sourceforge.net/projects/madwifi/)
|
||||||
|
Please note that you will need to add the correct path for
|
||||||
|
madwifi driver root directory in .config (see defconfig file for
|
||||||
|
an example: CFLAGS += -I<path>)
|
||||||
|
|
||||||
|
Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
|
||||||
|
(http://www.prism54.org/)
|
||||||
|
|
||||||
|
Any wired Ethernet driver for wired IEEE 802.1X authentication
|
||||||
|
(experimental code)
|
||||||
|
|
||||||
|
FreeBSD -current (with some kernel mods that have not yet been
|
||||||
|
committed when hostapd v0.3.0 was released)
|
||||||
|
BSD net80211 layer (e.g., Atheros driver)
|
||||||
|
|
||||||
|
|
||||||
|
Build configuration
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
In order to be able to build hostapd, you will need to create a build
|
||||||
|
time configuration file, .config that selects which optional
|
||||||
|
components are included. See defconfig file for example configuration
|
||||||
|
and list of available options.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IEEE 802.1X
|
||||||
|
===========
|
||||||
|
|
||||||
|
IEEE Std 802.1X-2001 is a standard for port-based network access
|
||||||
|
control. In case of IEEE 802.11 networks, a "virtual port" is used
|
||||||
|
between each associated station and the AP. IEEE 802.11 specifies
|
||||||
|
minimal authentication mechanism for stations, whereas IEEE 802.1X
|
||||||
|
introduces a extensible mechanism for authenticating and authorizing
|
||||||
|
users.
|
||||||
|
|
||||||
|
IEEE 802.1X uses elements called Supplicant, Authenticator, Port
|
||||||
|
Access Entity, and Authentication Server. Supplicant is a component in
|
||||||
|
a station and it performs the authentication with the Authentication
|
||||||
|
Server. An access point includes an Authenticator that relays the packets
|
||||||
|
between a Supplicant and an Authentication Server. In addition, it has a
|
||||||
|
Port Access Entity (PAE) with Authenticator functionality for
|
||||||
|
controlling the virtual port authorization, i.e., whether to accept
|
||||||
|
packets from or to the station.
|
||||||
|
|
||||||
|
IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
|
||||||
|
between a Supplicant and an Authenticator are sent using EAP over LAN
|
||||||
|
(EAPOL) and the Authenticator relays these frames to the Authentication
|
||||||
|
Server (and similarly, relays the messages from the Authentication
|
||||||
|
Server to the Supplicant). The Authentication Server can be colocated with the
|
||||||
|
Authenticator, in which case there is no need for additional protocol
|
||||||
|
for EAP frame transmission. However, a more common configuration is to
|
||||||
|
use an external Authentication Server and encapsulate EAP frame in the
|
||||||
|
frames used by that server. RADIUS is suitable for this, but IEEE
|
||||||
|
802.1X would also allow other mechanisms.
|
||||||
|
|
||||||
|
Host AP driver includes PAE functionality in the kernel driver. It
|
||||||
|
is a relatively simple mechanism for denying normal frames going to
|
||||||
|
or coming from an unauthorized port. PAE allows IEEE 802.1X related
|
||||||
|
frames to be passed between the Supplicant and the Authenticator even
|
||||||
|
on an unauthorized port.
|
||||||
|
|
||||||
|
User space daemon, hostapd, includes Authenticator functionality. It
|
||||||
|
receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
|
||||||
|
device that is also used with IEEE 802.11 management frames. The
|
||||||
|
frames to the Supplicant are sent using the same device.
|
||||||
|
|
||||||
|
The normal configuration of the Authenticator would use an external
|
||||||
|
Authentication Server. hostapd supports RADIUS encapsulation of EAP
|
||||||
|
packets, so the Authentication Server should be a RADIUS server, like
|
||||||
|
FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
|
||||||
|
relays the frames between the Supplicant and the Authentication
|
||||||
|
Server. It also controls the PAE functionality in the kernel driver by
|
||||||
|
controlling virtual port authorization, i.e., station-AP
|
||||||
|
connection, based on the IEEE 802.1X state.
|
||||||
|
|
||||||
|
When a station would like to use the services of an access point, it
|
||||||
|
will first perform IEEE 802.11 authentication. This is normally done
|
||||||
|
with open systems authentication, so there is no security. After
|
||||||
|
this, IEEE 802.11 association is performed. If IEEE 802.1X is
|
||||||
|
configured to be used, the virtual port for the station is set in
|
||||||
|
Unauthorized state and only IEEE 802.1X frames are accepted at this
|
||||||
|
point. The Authenticator will then ask the Supplicant to authenticate
|
||||||
|
with the Authentication Server. After this is completed successfully,
|
||||||
|
the virtual port is set to Authorized state and frames from and to the
|
||||||
|
station are accepted.
|
||||||
|
|
||||||
|
Host AP configuration for IEEE 802.1X
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
The user space daemon has its own configuration file that can be used to
|
||||||
|
define AP options. Distribution package contains an example
|
||||||
|
configuration file (hostapd/hostapd.conf) that can be used as a basis
|
||||||
|
for configuration. It includes examples of all supported configuration
|
||||||
|
options and short description of each option. hostapd should be started
|
||||||
|
with full path to the configuration file as the command line argument,
|
||||||
|
e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
|
||||||
|
LAN card, you can use one hostapd process for multiple interfaces by
|
||||||
|
giving a list of configuration files (one per interface) in the command
|
||||||
|
line.
|
||||||
|
|
||||||
|
hostapd includes a minimal co-located IEEE 802.1X server which can be
|
||||||
|
used to test IEEE 802.1X authentication. However, it should not be
|
||||||
|
used in normal use since it does not provide any security. This can be
|
||||||
|
configured by setting ieee8021x and minimal_eap options in the
|
||||||
|
configuration file.
|
||||||
|
|
||||||
|
An external Authentication Server (RADIUS) is configured with
|
||||||
|
auth_server_{addr,port,shared_secret} options. In addition,
|
||||||
|
ieee8021x and own_ip_addr must be set for this mode. With such
|
||||||
|
configuration, the co-located Authentication Server is not used and EAP
|
||||||
|
frames will be relayed using EAPOL between the Supplicant and the
|
||||||
|
Authenticator and RADIUS encapsulation between the Authenticator and
|
||||||
|
the Authentication Server. Other than this, the functionality is similar
|
||||||
|
to the case with the co-located Authentication Server.
|
||||||
|
|
||||||
|
Authentication Server and Supplicant
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
|
||||||
|
Authentication Server with hostapd Authenticator. FreeRADIUS
|
||||||
|
(http://www.freeradius.org/) has been successfully tested with hostapd
|
||||||
|
Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
|
||||||
|
XP Supplicants. EAP/TLS was used with Xsupplicant and
|
||||||
|
EAP/MD5-Challenge with Windows XP.
|
||||||
|
|
||||||
|
http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
|
||||||
|
about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
|
||||||
|
Cisco access point with Host AP driver, hostapd daemon, and a Prism2
|
||||||
|
card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
|
||||||
|
about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
|
||||||
|
configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
|
||||||
|
EAP/TLS use with WinXP Supplicant.
|
||||||
|
|
||||||
|
Automatic WEP key configuration
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
EAP/TLS generates a session key that can be used to send WEP keys from
|
||||||
|
an AP to authenticated stations. The Authenticator in hostapd can be
|
||||||
|
configured to automatically select a random default/broadcast key
|
||||||
|
(shared by all authenticated stations) with wep_key_len_broadcast
|
||||||
|
option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
|
||||||
|
wep_key_len_unicast option can be used to configure individual unicast
|
||||||
|
keys for stations. This requires support for individual keys in the
|
||||||
|
station driver.
|
||||||
|
|
||||||
|
WEP keys can be automatically updated by configuring rekeying. This
|
||||||
|
will improve security of the network since same WEP key will only be
|
||||||
|
used for a limited period of time. wep_rekey_period option sets the
|
||||||
|
interval for rekeying in seconds.
|
||||||
|
|
||||||
|
|
||||||
|
WPA/WPA2
|
||||||
|
========
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
Supported WPA/IEEE 802.11i features:
|
||||||
|
- WPA-PSK ("WPA-Personal")
|
||||||
|
- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
|
||||||
|
- key management for CCMP, TKIP, WEP104, WEP40
|
||||||
|
- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
|
||||||
|
|
||||||
|
WPA
|
||||||
|
---
|
||||||
|
|
||||||
|
The original security mechanism of IEEE 802.11 standard was not
|
||||||
|
designed to be strong and has proved to be insufficient for most
|
||||||
|
networks that require some kind of security. Task group I (Security)
|
||||||
|
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
|
||||||
|
to address the flaws of the base standard and has in practice
|
||||||
|
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
|
||||||
|
802.11 standard was approved in June 2004 and this amendment is likely
|
||||||
|
to be published in July 2004.
|
||||||
|
|
||||||
|
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
|
||||||
|
IEEE 802.11i work (draft 3.0) to define a subset of the security
|
||||||
|
enhancements that can be implemented with existing wlan hardware. This
|
||||||
|
is called Wi-Fi Protected Access<TM> (WPA). This has now become a
|
||||||
|
mandatory component of interoperability testing and certification done
|
||||||
|
by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
|
||||||
|
site (http://www.wi-fi.org/OpenSection/protected_access.asp).
|
||||||
|
|
||||||
|
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
|
||||||
|
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
|
||||||
|
24-bit initialization vector (IV), and CRC32 to protect against packet
|
||||||
|
forgery. All these choices have proven to be insufficient: key space is
|
||||||
|
too small against current attacks, RC4 key scheduling is insufficient
|
||||||
|
(beginning of the pseudorandom stream should be skipped), IV space is
|
||||||
|
too small and IV reuse makes attacks easier, there is no replay
|
||||||
|
protection, and non-keyed authentication does not protect against bit
|
||||||
|
flipping packet data.
|
||||||
|
|
||||||
|
WPA is an intermediate solution for the security issues. It uses
|
||||||
|
Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
|
||||||
|
compromise on strong security and possibility to use existing
|
||||||
|
hardware. It still uses RC4 for the encryption like WEP, but with
|
||||||
|
per-packet RC4 keys. In addition, it implements replay protection,
|
||||||
|
keyed packet authentication mechanism (Michael MIC).
|
||||||
|
|
||||||
|
Keys can be managed using two different mechanisms. WPA can either use
|
||||||
|
an external authentication server (e.g., RADIUS) and EAP just like
|
||||||
|
IEEE 802.1X is using or pre-shared keys without need for additional
|
||||||
|
servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
|
||||||
|
respectively. Both mechanisms will generate a master session key for
|
||||||
|
the Authenticator (AP) and Supplicant (client station).
|
||||||
|
|
||||||
|
WPA implements a new key handshake (4-Way Handshake and Group Key
|
||||||
|
Handshake) for generating and exchanging data encryption keys between
|
||||||
|
the Authenticator and Supplicant. This handshake is also used to
|
||||||
|
verify that both Authenticator and Supplicant know the master session
|
||||||
|
key. These handshakes are identical regardless of the selected key
|
||||||
|
management mechanism (only the method for generating master session
|
||||||
|
key changes).
|
||||||
|
|
||||||
|
|
||||||
|
IEEE 802.11i / WPA2
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The design for parts of IEEE 802.11i that were not included in WPA has
|
||||||
|
finished (May 2004) and this amendment to IEEE 802.11 was approved in
|
||||||
|
June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
|
||||||
|
version of WPA called WPA2. This includes, e.g., support for more
|
||||||
|
robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
|
||||||
|
to replace TKIP and optimizations for handoff (reduced number of
|
||||||
|
messages in initial key handshake, pre-authentication, and PMKSA caching).
|
||||||
|
|
||||||
|
Some wireless LAN vendors are already providing support for CCMP in
|
||||||
|
their WPA products. There is no "official" interoperability
|
||||||
|
certification for CCMP and/or mixed modes using both TKIP and CCMP, so
|
||||||
|
some interoperability issues can be expected even though many
|
||||||
|
combinations seem to be working with equipment from different vendors.
|
||||||
|
Testing for WPA2 is likely to start during the second half of 2004.
|
||||||
|
|
||||||
|
hostapd configuration for WPA/WPA2
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
# Enable WPA. Setting this variable configures the AP to require WPA (either
|
||||||
|
# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
|
||||||
|
# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
|
||||||
|
# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
|
||||||
|
# RADIUS authentication server must be configured, and WPA-EAP must be included
|
||||||
|
# in wpa_key_mgmt.
|
||||||
|
# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
|
||||||
|
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||||
|
# bit0 = WPA
|
||||||
|
# bit1 = IEEE 802.11i/RSN (WPA2)
|
||||||
|
#wpa=1
|
||||||
|
|
||||||
|
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||||
|
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||||
|
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
|
||||||
|
# so the PSK changes when ASCII passphrase is used and the SSID is changed.
|
||||||
|
#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||||
|
#wpa_passphrase=secret passphrase
|
||||||
|
|
||||||
|
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||||
|
# entries are separated with a space.
|
||||||
|
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||||
|
|
||||||
|
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||||
|
# (unicast packets). This is a space separated list of algorithms:
|
||||||
|
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
|
||||||
|
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
|
||||||
|
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
|
||||||
|
# is automatically selected based on this configuration. If only CCMP is
|
||||||
|
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||||
|
# TKIP will be used as the group cipher.
|
||||||
|
#wpa_pairwise=TKIP CCMP
|
||||||
|
|
||||||
|
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||||
|
# seconds.
|
||||||
|
#wpa_group_rekey=600
|
||||||
|
|
||||||
|
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||||
|
# (in seconds).
|
||||||
|
#wpa_gmk_rekey=86400
|
||||||
|
|
||||||
|
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||||
|
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||||
|
# authentication and key handshake before actually associating with a new AP.
|
||||||
|
#rsn_preauth=1
|
||||||
|
#
|
||||||
|
# Space separated list of interfaces from which pre-authentication frames are
|
||||||
|
# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
|
||||||
|
# interface that are used for connections to other APs. This could include
|
||||||
|
# wired interfaces and WDS links. The normal wireless data interface towards
|
||||||
|
# associated stations (e.g., wlan0) should not be added, since
|
||||||
|
# pre-authentication is only used with APs other than the currently associated
|
||||||
|
# one.
|
||||||
|
#rsn_preauth_interfaces=eth0
|
466
hostapd/accounting.c
Normal file
466
hostapd/accounting.c
Normal file
|
@ -0,0 +1,466 @@
|
||||||
|
/*
|
||||||
|
* hostapd / RADIUS Accounting
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "radius/radius.h"
|
||||||
|
#include "radius/radius_client.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "accounting.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Default interval in seconds for polling TX/RX octets from the driver if
|
||||||
|
* STA is not using interim accounting. This detects wrap arounds for
|
||||||
|
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
|
||||||
|
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
|
||||||
|
|
||||||
|
/* from ieee802_1x.c */
|
||||||
|
const char *radius_mode_txt(struct hostapd_data *hapd);
|
||||||
|
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
|
||||||
|
|
||||||
|
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta,
|
||||||
|
int status_type)
|
||||||
|
{
|
||||||
|
struct radius_msg *msg;
|
||||||
|
char buf[128];
|
||||||
|
u8 *val;
|
||||||
|
size_t len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
|
||||||
|
radius_client_get_id(hapd->radius));
|
||||||
|
if (msg == NULL) {
|
||||||
|
printf("Could not create net RADIUS packet\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta) {
|
||||||
|
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), "%08X-%08X",
|
||||||
|
sta->acct_session_id_hi, sta->acct_session_id_lo);
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
printf("Could not add Acct-Session-Id\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
|
||||||
|
status_type)) {
|
||||||
|
printf("Could not add Acct-Status-Type\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
|
||||||
|
hapd->conf->ieee802_1x ?
|
||||||
|
RADIUS_ACCT_AUTHENTIC_RADIUS :
|
||||||
|
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
|
||||||
|
printf("Could not add Acct-Authentic\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta) {
|
||||||
|
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
|
||||||
|
if (!val) {
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
val = (u8 *) buf;
|
||||||
|
len = os_strlen(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
|
||||||
|
len)) {
|
||||||
|
printf("Could not add User-Name\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||||
|
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||||
|
printf("Could not add NAS-IP-Address\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6
|
||||||
|
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||||
|
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||||
|
printf("Could not add NAS-IPv6-Address\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
|
if (hapd->conf->nas_identifier &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||||
|
(u8 *) hapd->conf->nas_identifier,
|
||||||
|
os_strlen(hapd->conf->nas_identifier))) {
|
||||||
|
printf("Could not add NAS-Identifier\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta &&
|
||||||
|
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
|
||||||
|
printf("Could not add NAS-Port\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
|
||||||
|
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
printf("Could not add Called-Station-Id\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta) {
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
printf("Could not add Calling-Station-Id\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(
|
||||||
|
msg, RADIUS_ATTR_NAS_PORT_TYPE,
|
||||||
|
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
|
||||||
|
printf("Could not add NAS-Port-Type\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
|
||||||
|
radius_sta_rate(hapd, sta) / 2,
|
||||||
|
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
|
||||||
|
radius_mode_txt(hapd));
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
printf("Could not add Connect-Info\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
|
||||||
|
i);
|
||||||
|
if (val == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
|
||||||
|
val, len)) {
|
||||||
|
printf("Could not add Class\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
radius_msg_free(msg);
|
||||||
|
os_free(msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int accounting_sta_update_stats(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta,
|
||||||
|
struct hostap_sta_driver_data *data)
|
||||||
|
{
|
||||||
|
if (hostapd_read_sta_data(hapd, data, sta->addr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sta->last_rx_bytes > data->rx_bytes)
|
||||||
|
sta->acct_input_gigawords++;
|
||||||
|
if (sta->last_tx_bytes > data->tx_bytes)
|
||||||
|
sta->acct_output_gigawords++;
|
||||||
|
sta->last_rx_bytes = data->rx_bytes;
|
||||||
|
sta->last_tx_bytes = data->tx_bytes;
|
||||||
|
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
|
||||||
|
"Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
|
||||||
|
"Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
|
||||||
|
sta->last_rx_bytes, sta->acct_input_gigawords,
|
||||||
|
sta->last_tx_bytes, sta->acct_output_gigawords);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
int interval;
|
||||||
|
|
||||||
|
if (sta->acct_interim_interval) {
|
||||||
|
accounting_sta_interim(hapd, sta);
|
||||||
|
interval = sta->acct_interim_interval;
|
||||||
|
} else {
|
||||||
|
struct hostap_sta_driver_data data;
|
||||||
|
accounting_sta_update_stats(hapd, sta, &data);
|
||||||
|
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
eloop_register_timeout(interval, 0, accounting_interim_update,
|
||||||
|
hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void accounting_sta_start(struct hostapd_data *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->radius->acct_server)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sta->acct_interim_interval)
|
||||||
|
interval = sta->acct_interim_interval;
|
||||||
|
else
|
||||||
|
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
|
||||||
|
eloop_register_timeout(interval, 0, accounting_interim_update,
|
||||||
|
hapd, sta);
|
||||||
|
|
||||||
|
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
|
||||||
|
if (msg)
|
||||||
|
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
|
||||||
|
|
||||||
|
sta->acct_session_started = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void accounting_sta_report(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int stop)
|
||||||
|
{
|
||||||
|
struct radius_msg *msg;
|
||||||
|
int cause = sta->acct_terminate_cause;
|
||||||
|
struct hostap_sta_driver_data data;
|
||||||
|
u32 gigawords;
|
||||||
|
|
||||||
|
if (!hapd->conf->radius->acct_server)
|
||||||
|
return;
|
||||||
|
|
||||||
|
msg = accounting_msg(hapd, sta,
|
||||||
|
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
|
||||||
|
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
|
||||||
|
if (!msg) {
|
||||||
|
printf("Could not create RADIUS Accounting message\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
|
||||||
|
time(NULL) - sta->acct_session_start)) {
|
||||||
|
printf("Could not add Acct-Session-Time\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
|
||||||
|
if (!radius_msg_add_attr_int32(msg,
|
||||||
|
RADIUS_ATTR_ACCT_INPUT_PACKETS,
|
||||||
|
data.rx_packets)) {
|
||||||
|
printf("Could not add Acct-Input-Packets\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!radius_msg_add_attr_int32(msg,
|
||||||
|
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
|
||||||
|
data.tx_packets)) {
|
||||||
|
printf("Could not add Acct-Output-Packets\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!radius_msg_add_attr_int32(msg,
|
||||||
|
RADIUS_ATTR_ACCT_INPUT_OCTETS,
|
||||||
|
data.rx_bytes)) {
|
||||||
|
printf("Could not add Acct-Input-Octets\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
gigawords = sta->acct_input_gigawords;
|
||||||
|
#if __WORDSIZE == 64
|
||||||
|
gigawords += data.rx_bytes >> 32;
|
||||||
|
#endif
|
||||||
|
if (gigawords &&
|
||||||
|
!radius_msg_add_attr_int32(
|
||||||
|
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
|
||||||
|
gigawords)) {
|
||||||
|
printf("Could not add Acct-Input-Gigawords\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!radius_msg_add_attr_int32(msg,
|
||||||
|
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
|
||||||
|
data.tx_bytes)) {
|
||||||
|
printf("Could not add Acct-Output-Octets\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
gigawords = sta->acct_output_gigawords;
|
||||||
|
#if __WORDSIZE == 64
|
||||||
|
gigawords += data.tx_bytes >> 32;
|
||||||
|
#endif
|
||||||
|
if (gigawords &&
|
||||||
|
!radius_msg_add_attr_int32(
|
||||||
|
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
|
||||||
|
gigawords)) {
|
||||||
|
printf("Could not add Acct-Output-Gigawords\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
|
||||||
|
time(NULL))) {
|
||||||
|
printf("Could not add Event-Timestamp\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eloop_terminated())
|
||||||
|
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
|
||||||
|
|
||||||
|
if (stop && cause &&
|
||||||
|
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
|
||||||
|
cause)) {
|
||||||
|
printf("Could not add Acct-Terminate-Cause\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
radius_client_send(hapd->radius, msg,
|
||||||
|
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
|
||||||
|
sta->addr);
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
radius_msg_free(msg);
|
||||||
|
os_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
if (sta->acct_session_started)
|
||||||
|
accounting_sta_report(hapd, sta, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
if (sta->acct_session_started) {
|
||||||
|
accounting_sta_report(hapd, sta, 1);
|
||||||
|
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
|
||||||
|
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(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||||
|
printf("Incoming RADIUS packet did not have correct "
|
||||||
|
"Authenticator - dropped\n");
|
||||||
|
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RADIUS_RX_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||||
|
{
|
||||||
|
struct radius_msg *msg;
|
||||||
|
|
||||||
|
if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Inform RADIUS server that accounting will start/stop so that the
|
||||||
|
* server can close old accounting sessions. */
|
||||||
|
msg = accounting_msg(hapd, NULL,
|
||||||
|
on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
|
||||||
|
RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
|
||||||
|
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
|
||||||
|
{
|
||||||
|
printf("Could not add Acct-Terminate-Cause\n");
|
||||||
|
radius_msg_free(msg);
|
||||||
|
os_free(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int accounting_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
/* Acct-Session-Id should be unique over reboots. If reliable clock is
|
||||||
|
* not available, this could be replaced with reboot counter, etc. */
|
||||||
|
hapd->acct_session_id_hi = time(NULL);
|
||||||
|
|
||||||
|
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
||||||
|
accounting_receive, hapd))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
accounting_report_state(hapd, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void accounting_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
accounting_report_state(hapd, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int accounting_reconfig(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *oldconf)
|
||||||
|
{
|
||||||
|
if (!hapd->radius_client_reconfigured)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
accounting_deinit(hapd);
|
||||||
|
return accounting_init(hapd);
|
||||||
|
}
|
27
hostapd/accounting.h
Normal file
27
hostapd/accounting.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* hostapd / RADIUS Accounting
|
||||||
|
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ACCOUNTING_H
|
||||||
|
#define ACCOUNTING_H
|
||||||
|
|
||||||
|
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
int accounting_init(struct hostapd_data *hapd);
|
||||||
|
void accounting_deinit(struct hostapd_data *hapd);
|
||||||
|
int accounting_reconfig(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *oldconf);
|
||||||
|
|
||||||
|
#endif /* ACCOUNTING_H */
|
111
hostapd/ap.h
Normal file
111
hostapd/ap.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Station table data structures
|
||||||
|
* Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef 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_SHORT_PREAMBLE BIT(7)
|
||||||
|
#define WLAN_STA_PREAUTH BIT(8)
|
||||||
|
#define WLAN_STA_WME BIT(9)
|
||||||
|
#define WLAN_STA_NONERP BIT(31)
|
||||||
|
|
||||||
|
/* Maximum number of supported rates (from both Supported Rates and Extended
|
||||||
|
* Supported Rates IEs). */
|
||||||
|
#define WLAN_SUPP_RATES_MAX 32
|
||||||
|
|
||||||
|
|
||||||
|
struct sta_info {
|
||||||
|
struct sta_info *next; /* next entry in sta list */
|
||||||
|
struct sta_info *hnext; /* next entry in hash table list */
|
||||||
|
u8 addr[6];
|
||||||
|
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
|
||||||
|
u32 flags;
|
||||||
|
u16 capability;
|
||||||
|
u16 listen_interval; /* or beacon_int for APs */
|
||||||
|
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||||
|
int supported_rates_len;
|
||||||
|
|
||||||
|
unsigned int nonerp_set:1;
|
||||||
|
unsigned int no_short_slot_time_set:1;
|
||||||
|
unsigned int no_short_preamble_set:1;
|
||||||
|
|
||||||
|
u16 auth_alg;
|
||||||
|
u8 previous_ap[6];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
|
||||||
|
} timeout_next;
|
||||||
|
|
||||||
|
/* IEEE 802.1X related data */
|
||||||
|
struct eapol_state_machine *eapol_sm;
|
||||||
|
|
||||||
|
/* IEEE 802.11f (IAPP) related data */
|
||||||
|
struct ieee80211_mgmt *last_assoc_req;
|
||||||
|
|
||||||
|
u32 acct_session_id_hi;
|
||||||
|
u32 acct_session_id_lo;
|
||||||
|
time_t acct_session_start;
|
||||||
|
int acct_session_started;
|
||||||
|
int acct_terminate_cause; /* Acct-Terminate-Cause */
|
||||||
|
int acct_interim_interval; /* Acct-Interim-Interval */
|
||||||
|
|
||||||
|
unsigned long last_rx_bytes;
|
||||||
|
unsigned long last_tx_bytes;
|
||||||
|
u32 acct_input_gigawords; /* Acct-Input-Gigawords */
|
||||||
|
u32 acct_output_gigawords; /* Acct-Output-Gigawords */
|
||||||
|
|
||||||
|
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
|
||||||
|
|
||||||
|
struct wpa_state_machine *wpa_sm;
|
||||||
|
struct rsn_preauth_interface *preauth_iface;
|
||||||
|
|
||||||
|
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
|
||||||
|
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
|
||||||
|
|
||||||
|
int vlan_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
|
||||||
|
* (8802.11 limitation) */
|
||||||
|
#define MAX_AID_TABLE_SIZE 128
|
||||||
|
|
||||||
|
#define STA_HASH_SIZE 256
|
||||||
|
#define STA_HASH(sta) (sta[5])
|
||||||
|
|
||||||
|
|
||||||
|
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
|
||||||
|
* passed since last received frame from the station, a nullfunc data frame is
|
||||||
|
* sent to the station. If this frame is not acknowledged and no other frames
|
||||||
|
* have been received, the station will be disassociated after
|
||||||
|
* AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
|
||||||
|
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
|
||||||
|
#define AP_MAX_INACTIVITY (5 * 60)
|
||||||
|
#define AP_DISASSOC_DELAY (1)
|
||||||
|
#define AP_DEAUTH_DELAY (1)
|
||||||
|
/* Number of seconds to keep STA entry with Authenticated flag after it has
|
||||||
|
* been disassociated. */
|
||||||
|
#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
|
||||||
|
/* Number of seconds to keep STA entry after it has been deauthenticated. */
|
||||||
|
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
|
||||||
|
|
||||||
|
#endif /* AP_H */
|
458
hostapd/ap_list.c
Normal file
458
hostapd/ap_list.c
Normal file
|
@ -0,0 +1,458 @@
|
||||||
|
/*
|
||||||
|
* hostapd / AP table
|
||||||
|
* Copyright 2002-2003, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "ap_list.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee80211_frame_info {
|
||||||
|
u32 version;
|
||||||
|
u32 length;
|
||||||
|
u64 mactime;
|
||||||
|
u64 hosttime;
|
||||||
|
u32 phytype;
|
||||||
|
u32 channel;
|
||||||
|
u32 datarate;
|
||||||
|
u32 antenna;
|
||||||
|
u32 priority;
|
||||||
|
u32 ssi_type;
|
||||||
|
u32 ssi_signal;
|
||||||
|
u32 ssi_noise;
|
||||||
|
u32 preamble;
|
||||||
|
u32 encoding;
|
||||||
|
|
||||||
|
/* Note: this structure is otherwise identical to capture format used
|
||||||
|
* in linux-wlan-ng, but this additional field is used to provide meta
|
||||||
|
* data about the frame to hostapd. This was the easiest method for
|
||||||
|
* providing this information, but this might change in the future. */
|
||||||
|
u32 msg_type;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
enum ieee80211_phytype {
|
||||||
|
ieee80211_phytype_fhss_dot11_97 = 1,
|
||||||
|
ieee80211_phytype_dsss_dot11_97 = 2,
|
||||||
|
ieee80211_phytype_irbaseband = 3,
|
||||||
|
ieee80211_phytype_dsss_dot11_b = 4,
|
||||||
|
ieee80211_phytype_pbcc_dot11_b = 5,
|
||||||
|
ieee80211_phytype_ofdm_dot11_g = 6,
|
||||||
|
ieee80211_phytype_pbcc_dot11_g = 7,
|
||||||
|
ieee80211_phytype_ofdm_dot11_a = 8,
|
||||||
|
ieee80211_phytype_dsss_dot11_turbog = 255,
|
||||||
|
ieee80211_phytype_dsss_dot11_turbo = 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* AP list is a double linked list with head->prev pointing to the end of the
|
||||||
|
* list and tail->next = NULL. Entries are moved to the head of the list
|
||||||
|
* whenever a beacon has been received from the AP in question. The tail entry
|
||||||
|
* in this link will thus be the least recently used entry. */
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
|
||||||
|
|
||||||
|
/* TODO: could send a notification message to an external program that
|
||||||
|
* would then determine whether a rogue AP has been detected */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
|
||||||
|
|
||||||
|
/* TODO: could send a notification message to an external program */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
|
||||||
|
ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
|
||||||
|
iface->conf->channel != ap->channel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
|
||||||
|
int rate = (ap->supported_rates[i] & 0x7f) * 5;
|
||||||
|
if (rate == 60 || rate == 90 || rate > 110)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
|
||||||
|
{
|
||||||
|
struct ap_info *s;
|
||||||
|
|
||||||
|
s = iface->ap_hash[STA_HASH(ap)];
|
||||||
|
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
|
||||||
|
s = s->hnext;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
if (iface->ap_list) {
|
||||||
|
ap->prev = iface->ap_list->prev;
|
||||||
|
iface->ap_list->prev = ap;
|
||||||
|
} else
|
||||||
|
ap->prev = ap;
|
||||||
|
ap->next = iface->ap_list;
|
||||||
|
iface->ap_list = ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
if (iface->ap_list == ap)
|
||||||
|
iface->ap_list = ap->next;
|
||||||
|
else
|
||||||
|
ap->prev->next = ap->next;
|
||||||
|
|
||||||
|
if (ap->next)
|
||||||
|
ap->next->prev = ap->prev;
|
||||||
|
else if (iface->ap_list)
|
||||||
|
iface->ap_list->prev = ap->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_iter_list_add(struct hostapd_iface *iface,
|
||||||
|
struct ap_info *ap)
|
||||||
|
{
|
||||||
|
if (iface->ap_iter_list) {
|
||||||
|
ap->iter_prev = iface->ap_iter_list->iter_prev;
|
||||||
|
iface->ap_iter_list->iter_prev = ap;
|
||||||
|
} else
|
||||||
|
ap->iter_prev = ap;
|
||||||
|
ap->iter_next = iface->ap_iter_list;
|
||||||
|
iface->ap_iter_list = ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_iter_list_del(struct hostapd_iface *iface,
|
||||||
|
struct ap_info *ap)
|
||||||
|
{
|
||||||
|
if (iface->ap_iter_list == ap)
|
||||||
|
iface->ap_iter_list = ap->iter_next;
|
||||||
|
else
|
||||||
|
ap->iter_prev->iter_next = ap->iter_next;
|
||||||
|
|
||||||
|
if (ap->iter_next)
|
||||||
|
ap->iter_next->iter_prev = ap->iter_prev;
|
||||||
|
else if (iface->ap_iter_list)
|
||||||
|
iface->ap_iter_list->iter_prev = ap->iter_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
|
||||||
|
iface->ap_hash[STA_HASH(ap->addr)] = ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
struct ap_info *s;
|
||||||
|
|
||||||
|
s = iface->ap_hash[STA_HASH(ap->addr)];
|
||||||
|
if (s == NULL) return;
|
||||||
|
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
|
||||||
|
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (s->hnext != NULL &&
|
||||||
|
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
|
||||||
|
s = s->hnext;
|
||||||
|
if (s->hnext != NULL)
|
||||||
|
s->hnext = s->hnext->hnext;
|
||||||
|
else
|
||||||
|
printf("AP: could not remove AP " MACSTR " from hash table\n",
|
||||||
|
MAC2STR(ap->addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
|
||||||
|
{
|
||||||
|
ap_ap_hash_del(iface, ap);
|
||||||
|
ap_ap_list_del(iface, ap);
|
||||||
|
ap_ap_iter_list_del(iface, ap);
|
||||||
|
|
||||||
|
iface->num_ap--;
|
||||||
|
os_free(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_free_aps(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
struct ap_info *ap, *prev;
|
||||||
|
|
||||||
|
ap = iface->ap_list;
|
||||||
|
|
||||||
|
while (ap) {
|
||||||
|
prev = ap;
|
||||||
|
ap = ap->next;
|
||||||
|
ap_free_ap(iface, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
iface->ap_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ap_ap_for_each(struct hostapd_iface *iface,
|
||||||
|
int (*func)(struct ap_info *s, void *data), void *data)
|
||||||
|
{
|
||||||
|
struct ap_info *s;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
s = iface->ap_list;
|
||||||
|
|
||||||
|
while (s) {
|
||||||
|
ret = func(s, data);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
s = s->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
|
||||||
|
{
|
||||||
|
struct ap_info *ap;
|
||||||
|
|
||||||
|
ap = os_zalloc(sizeof(struct ap_info));
|
||||||
|
if (ap == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* initialize AP info data */
|
||||||
|
os_memcpy(ap->addr, addr, ETH_ALEN);
|
||||||
|
ap_ap_list_add(iface, ap);
|
||||||
|
iface->num_ap++;
|
||||||
|
ap_ap_hash_add(iface, ap);
|
||||||
|
ap_ap_iter_list_add(iface, ap);
|
||||||
|
|
||||||
|
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
|
||||||
|
MACSTR " from AP table", MAC2STR(ap->prev->addr));
|
||||||
|
if (iface->conf->passive_scan_interval > 0)
|
||||||
|
ap_list_expired_ap(iface, ap->prev);
|
||||||
|
ap_free_ap(iface, ap->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||||
|
struct ieee80211_mgmt *mgmt,
|
||||||
|
struct ieee802_11_elems *elems,
|
||||||
|
struct hostapd_frame_info *fi)
|
||||||
|
{
|
||||||
|
struct ap_info *ap;
|
||||||
|
int new_ap = 0;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (iface->conf->ap_table_max_size < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ap = ap_get_ap(iface, mgmt->bssid);
|
||||||
|
if (!ap) {
|
||||||
|
ap = ap_ap_add(iface, mgmt->bssid);
|
||||||
|
if (!ap) {
|
||||||
|
printf("Failed to allocate AP information entry\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new_ap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
|
||||||
|
ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
|
||||||
|
|
||||||
|
if (elems->ssid) {
|
||||||
|
len = elems->ssid_len;
|
||||||
|
if (len >= sizeof(ap->ssid))
|
||||||
|
len = sizeof(ap->ssid) - 1;
|
||||||
|
os_memcpy(ap->ssid, elems->ssid, len);
|
||||||
|
ap->ssid[len] = '\0';
|
||||||
|
ap->ssid_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
|
||||||
|
len = 0;
|
||||||
|
if (elems->supp_rates) {
|
||||||
|
len = elems->supp_rates_len;
|
||||||
|
if (len > WLAN_SUPP_RATES_MAX)
|
||||||
|
len = WLAN_SUPP_RATES_MAX;
|
||||||
|
os_memcpy(ap->supported_rates, elems->supp_rates, len);
|
||||||
|
}
|
||||||
|
if (elems->ext_supp_rates) {
|
||||||
|
int len2;
|
||||||
|
if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
|
||||||
|
len2 = WLAN_SUPP_RATES_MAX - len;
|
||||||
|
else
|
||||||
|
len2 = elems->ext_supp_rates_len;
|
||||||
|
os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
|
||||||
|
len2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->wpa = elems->wpa_ie != NULL;
|
||||||
|
|
||||||
|
if (elems->erp_info && elems->erp_info_len == 1)
|
||||||
|
ap->erp = elems->erp_info[0];
|
||||||
|
else
|
||||||
|
ap->erp = -1;
|
||||||
|
|
||||||
|
if (elems->ds_params && elems->ds_params_len == 1)
|
||||||
|
ap->channel = elems->ds_params[0];
|
||||||
|
else if (fi)
|
||||||
|
ap->channel = fi->channel;
|
||||||
|
|
||||||
|
ap->num_beacons++;
|
||||||
|
time(&ap->last_beacon);
|
||||||
|
if (fi) {
|
||||||
|
ap->phytype = fi->phytype;
|
||||||
|
ap->ssi_signal = fi->ssi_signal;
|
||||||
|
ap->datarate = fi->datarate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_ap) {
|
||||||
|
if (iface->conf->passive_scan_interval > 0)
|
||||||
|
ap_list_new_ap(iface, ap);
|
||||||
|
} else if (ap != iface->ap_list) {
|
||||||
|
/* move AP entry into the beginning of the list so that the
|
||||||
|
* oldest entry is always in the end of the list */
|
||||||
|
ap_ap_list_del(iface, ap);
|
||||||
|
ap_ap_list_add(iface, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iface->olbc &&
|
||||||
|
ap_list_beacon_olbc(iface, ap)) {
|
||||||
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
|
iface->olbc = 1;
|
||||||
|
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
|
||||||
|
"protection", MAC2STR(ap->addr));
|
||||||
|
ieee802_11_set_beacons(hapd->iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *iface = eloop_ctx;
|
||||||
|
time_t now;
|
||||||
|
struct ap_info *ap;
|
||||||
|
|
||||||
|
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||||
|
|
||||||
|
if (!iface->ap_list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
/* FIX: it looks like jkm-Purina ended up in busy loop in this
|
||||||
|
* function. Apparently, something can still cause a loop in the AP
|
||||||
|
* list.. */
|
||||||
|
|
||||||
|
while (iface->ap_list) {
|
||||||
|
ap = iface->ap_list->prev;
|
||||||
|
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
|
||||||
|
now)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (iface->conf->passive_scan_interval > 0)
|
||||||
|
ap_list_expired_ap(iface, ap);
|
||||||
|
ap_free_ap(iface, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iface->olbc) {
|
||||||
|
int olbc = 0;
|
||||||
|
ap = iface->ap_list;
|
||||||
|
while (ap) {
|
||||||
|
if (ap_list_beacon_olbc(iface, ap)) {
|
||||||
|
olbc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ap = ap->next;
|
||||||
|
}
|
||||||
|
if (!olbc) {
|
||||||
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
|
wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
|
||||||
|
iface->olbc = 0;
|
||||||
|
ieee802_11_set_beacons(hapd->iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ap_list_init(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_list_deinit(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(ap_list_timer, iface, NULL);
|
||||||
|
hostapd_free_aps(iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ap_list_reconfig(struct hostapd_iface *iface,
|
||||||
|
struct hostapd_config *oldconf)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
struct ap_info *ap;
|
||||||
|
|
||||||
|
if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
|
||||||
|
iface->conf->ap_table_expiration_time ==
|
||||||
|
oldconf->ap_table_expiration_time)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
|
||||||
|
while (iface->ap_list) {
|
||||||
|
ap = iface->ap_list->prev;
|
||||||
|
if (iface->num_ap <= iface->conf->ap_table_max_size &&
|
||||||
|
ap->last_beacon + iface->conf->ap_table_expiration_time >=
|
||||||
|
now)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (iface->conf->passive_scan_interval > 0)
|
||||||
|
ap_list_expired_ap(iface, iface->ap_list->prev);
|
||||||
|
ap_free_ap(iface, iface->ap_list->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
68
hostapd/ap_list.h
Normal file
68
hostapd/ap_list.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* hostapd / AP table
|
||||||
|
* Copyright 2002-2003, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AP_LIST_H
|
||||||
|
#define AP_LIST_H
|
||||||
|
|
||||||
|
struct ap_info {
|
||||||
|
/* Note: next/prev pointers are updated whenever a new beacon is
|
||||||
|
* received because these are used to find the least recently used
|
||||||
|
* entries. iter_next/iter_prev are updated only when adding new BSSes
|
||||||
|
* and when removing old ones. These should be used when iterating
|
||||||
|
* through the table in a manner that allows beacons to be received
|
||||||
|
* during the iteration. */
|
||||||
|
struct ap_info *next; /* next entry in AP list */
|
||||||
|
struct ap_info *prev; /* previous entry in AP list */
|
||||||
|
struct ap_info *hnext; /* next entry in hash table list */
|
||||||
|
struct ap_info *iter_next; /* next entry in AP iteration list */
|
||||||
|
struct ap_info *iter_prev; /* previous entry in AP iteration list */
|
||||||
|
u8 addr[6];
|
||||||
|
u16 beacon_int;
|
||||||
|
u16 capability;
|
||||||
|
u8 supported_rates[WLAN_SUPP_RATES_MAX];
|
||||||
|
u8 ssid[33];
|
||||||
|
size_t ssid_len;
|
||||||
|
int wpa;
|
||||||
|
int erp; /* ERP Info or -1 if ERP info element not present */
|
||||||
|
|
||||||
|
int phytype; /* .11a / .11b / .11g / Atheros Turbo */
|
||||||
|
int channel;
|
||||||
|
int datarate; /* in 100 kbps */
|
||||||
|
int ssi_signal;
|
||||||
|
|
||||||
|
unsigned int num_beacons; /* number of beacon frames received */
|
||||||
|
time_t last_beacon;
|
||||||
|
|
||||||
|
int already_seen; /* whether API call AP-NEW has already fetched
|
||||||
|
* information about this AP */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ieee802_11_elems;
|
||||||
|
struct hostapd_frame_info;
|
||||||
|
|
||||||
|
struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
|
||||||
|
int ap_ap_for_each(struct hostapd_iface *iface,
|
||||||
|
int (*func)(struct ap_info *s, void *data), void *data);
|
||||||
|
void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||||
|
struct ieee80211_mgmt *mgmt,
|
||||||
|
struct ieee802_11_elems *elems,
|
||||||
|
struct hostapd_frame_info *fi);
|
||||||
|
int ap_list_init(struct hostapd_iface *iface);
|
||||||
|
void ap_list_deinit(struct hostapd_iface *iface);
|
||||||
|
int ap_list_reconfig(struct hostapd_iface *iface,
|
||||||
|
struct hostapd_config *oldconf);
|
||||||
|
|
||||||
|
#endif /* AP_LIST_H */
|
418
hostapd/beacon.c
Normal file
418
hostapd/beacon.c
Normal file
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
|
||||||
|
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||||
|
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "wme.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "ieee802_11h.h"
|
||||||
|
|
||||||
|
|
||||||
|
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
u8 erp = 0;
|
||||||
|
|
||||||
|
if (hapd->iface->current_mode == NULL ||
|
||||||
|
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (hapd->iconf->cts_protection_type) {
|
||||||
|
case CTS_PROTECTION_FORCE_ENABLED:
|
||||||
|
erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
|
||||||
|
break;
|
||||||
|
case CTS_PROTECTION_FORCE_DISABLED:
|
||||||
|
erp = 0;
|
||||||
|
break;
|
||||||
|
case CTS_PROTECTION_AUTOMATIC:
|
||||||
|
if (hapd->iface->olbc)
|
||||||
|
erp |= ERP_INFO_USE_PROTECTION;
|
||||||
|
/* continue */
|
||||||
|
case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
|
||||||
|
if (hapd->iface->num_sta_non_erp > 0) {
|
||||||
|
erp |= ERP_INFO_NON_ERP_PRESENT |
|
||||||
|
ERP_INFO_USE_PROTECTION;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (hapd->iface->num_sta_no_short_preamble > 0)
|
||||||
|
erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
|
||||||
|
|
||||||
|
return erp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
{
|
||||||
|
*eid++ = WLAN_EID_DS_PARAMS;
|
||||||
|
*eid++ = 1;
|
||||||
|
*eid++ = hapd->iconf->channel;
|
||||||
|
return eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
{
|
||||||
|
if (hapd->iface->current_mode == NULL ||
|
||||||
|
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||||
|
return eid;
|
||||||
|
|
||||||
|
/* Set NonERP_present and use_protection bits if there
|
||||||
|
* are any associated NonERP stations. */
|
||||||
|
/* TODO: use_protection bit can be set to zero even if
|
||||||
|
* there are NonERP stations present. This optimization
|
||||||
|
* might be useful if NonERP stations are "quiet".
|
||||||
|
* See 802.11g/D6 E-1 for recommended practice.
|
||||||
|
* In addition, Non ERP present might be set, if AP detects Non ERP
|
||||||
|
* operation on other APs. */
|
||||||
|
|
||||||
|
/* Add ERP Information element */
|
||||||
|
*eid++ = WLAN_EID_ERP_INFO;
|
||||||
|
*eid++ = 1;
|
||||||
|
*eid++ = ieee802_11_erp_info(hapd);
|
||||||
|
|
||||||
|
return eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
|
||||||
|
int max_len)
|
||||||
|
{
|
||||||
|
u8 *pos = eid;
|
||||||
|
|
||||||
|
if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
|
||||||
|
max_len < 6)
|
||||||
|
return eid;
|
||||||
|
|
||||||
|
*pos++ = WLAN_EID_COUNTRY;
|
||||||
|
pos++; /* length will be set later */
|
||||||
|
os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
|
||||||
|
pos += 3;
|
||||||
|
|
||||||
|
if ((pos - eid) & 1)
|
||||||
|
*pos++ = 0; /* pad for 16-bit alignment */
|
||||||
|
|
||||||
|
eid[1] = (pos - eid) - 2;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!hapd->iface->dfs_enable)
|
||||||
|
return eid;
|
||||||
|
*eid++ = WLAN_EID_PWR_CONSTRAINT;
|
||||||
|
*eid++ = 1;
|
||||||
|
*eid++ = hapd->iface->pwr_const;
|
||||||
|
return eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!hapd->iface->dfs_enable)
|
||||||
|
return eid;
|
||||||
|
*eid++ = WLAN_EID_TPC_REPORT;
|
||||||
|
*eid++ = 2;
|
||||||
|
*eid++ = hapd->iface->tx_power; /* TX POWER */
|
||||||
|
*eid++ = 0; /* Link Margin */
|
||||||
|
return eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
|
||||||
|
return eid;
|
||||||
|
*eid++ = WLAN_EID_CHANNEL_SWITCH;
|
||||||
|
*eid++ = 3;
|
||||||
|
*eid++ = CHAN_SWITCH_MODE_QUIET;
|
||||||
|
*eid++ = hapd->iface->channel_switch; /* New channel */
|
||||||
|
/* 0 - very soon; 1 - before next TBTT; num - after num beacons */
|
||||||
|
*eid++ = 0;
|
||||||
|
return eid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
const u8 *ie;
|
||||||
|
size_t ielen;
|
||||||
|
|
||||||
|
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
|
||||||
|
if (ie == NULL || ielen > len)
|
||||||
|
return eid;
|
||||||
|
|
||||||
|
os_memcpy(eid, ie, ielen);
|
||||||
|
return eid + ielen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct ieee80211_mgmt *resp;
|
||||||
|
struct ieee802_11_elems elems;
|
||||||
|
char *ssid;
|
||||||
|
u8 *pos, *epos, *ie;
|
||||||
|
size_t ssid_len, ie_len;
|
||||||
|
struct sta_info *sta = NULL;
|
||||||
|
|
||||||
|
ie = mgmt->u.probe_req.variable;
|
||||||
|
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
|
||||||
|
|
||||||
|
if (!hapd->iconf->send_probe_response)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ieee802_11_parse_elems(hapd, ie, ie_len, &elems, 0) == ParseFailed)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
|
||||||
|
MAC2STR(mgmt->sa));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssid = NULL;
|
||||||
|
ssid_len = 0;
|
||||||
|
|
||||||
|
if ((!elems.ssid || !elems.supp_rates)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
|
||||||
|
"without SSID or supported rates element",
|
||||||
|
MAC2STR(mgmt->sa));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
|
||||||
|
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
|
||||||
|
"broadcast SSID ignored", MAC2STR(mgmt->sa));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, mgmt->sa);
|
||||||
|
|
||||||
|
if (elems.ssid_len == 0 ||
|
||||||
|
(elems.ssid_len == hapd->conf->ssid.ssid_len &&
|
||||||
|
os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
|
||||||
|
0)) {
|
||||||
|
ssid = hapd->conf->ssid.ssid;
|
||||||
|
ssid_len = hapd->conf->ssid.ssid_len;
|
||||||
|
if (sta)
|
||||||
|
sta->ssid_probe = &hapd->conf->ssid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ssid) {
|
||||||
|
if (!(mgmt->da[0] & 0x01)) {
|
||||||
|
char ssid_txt[33];
|
||||||
|
ieee802_11_print_ssid(ssid_txt, elems.ssid,
|
||||||
|
elems.ssid_len);
|
||||||
|
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
|
||||||
|
" for foreign SSID '%s'",
|
||||||
|
MAC2STR(mgmt->sa), ssid_txt);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: verify that supp_rates contains at least one matching rate
|
||||||
|
* with AP configuration */
|
||||||
|
#define MAX_PROBERESP_LEN 768
|
||||||
|
resp = os_zalloc(MAX_PROBERESP_LEN);
|
||||||
|
if (resp == NULL)
|
||||||
|
return;
|
||||||
|
epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
|
||||||
|
|
||||||
|
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||||
|
WLAN_FC_STYPE_PROBE_RESP);
|
||||||
|
os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
|
||||||
|
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
|
||||||
|
resp->u.probe_resp.beacon_int =
|
||||||
|
host_to_le16(hapd->iconf->beacon_int);
|
||||||
|
|
||||||
|
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||||
|
resp->u.probe_resp.capab_info =
|
||||||
|
host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
|
||||||
|
|
||||||
|
pos = resp->u.probe_resp.variable;
|
||||||
|
*pos++ = WLAN_EID_SSID;
|
||||||
|
*pos++ = ssid_len;
|
||||||
|
os_memcpy(pos, ssid, ssid_len);
|
||||||
|
pos += ssid_len;
|
||||||
|
|
||||||
|
/* Supported rates */
|
||||||
|
pos = hostapd_eid_supp_rates(hapd, pos);
|
||||||
|
|
||||||
|
/* DS Params */
|
||||||
|
pos = hostapd_eid_ds_params(hapd, pos);
|
||||||
|
|
||||||
|
pos = hostapd_eid_country(hapd, pos, epos - pos);
|
||||||
|
|
||||||
|
pos = hostapd_eid_power_constraint(hapd, pos);
|
||||||
|
pos = hostapd_eid_tpc_report(hapd, pos);
|
||||||
|
|
||||||
|
/* ERP Information element */
|
||||||
|
pos = hostapd_eid_erp_info(hapd, pos);
|
||||||
|
|
||||||
|
/* Extended supported rates */
|
||||||
|
pos = hostapd_eid_ext_supp_rates(hapd, pos);
|
||||||
|
|
||||||
|
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
|
||||||
|
|
||||||
|
/* Wi-Fi Wireless Multimedia Extensions */
|
||||||
|
if (hapd->conf->wme_enabled)
|
||||||
|
pos = hostapd_eid_wme(hapd, pos);
|
||||||
|
|
||||||
|
if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
|
||||||
|
perror("handle_probe_req: send");
|
||||||
|
|
||||||
|
os_free(resp);
|
||||||
|
|
||||||
|
wpa_printf(MSG_MSGDUMP, "STA " MACSTR " sent probe request for %s "
|
||||||
|
"SSID", MAC2STR(mgmt->sa),
|
||||||
|
elems.ssid_len == 0 ? "broadcast" : "our");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct ieee80211_mgmt *head;
|
||||||
|
u8 *pos, *tail, *tailpos;
|
||||||
|
int preamble;
|
||||||
|
u16 capab_info;
|
||||||
|
size_t head_len, tail_len;
|
||||||
|
int cts_protection = ((ieee802_11_erp_info(hapd) &
|
||||||
|
ERP_INFO_USE_PROTECTION) ? 1 : 0);
|
||||||
|
|
||||||
|
#define BEACON_HEAD_BUF_SIZE 256
|
||||||
|
#define BEACON_TAIL_BUF_SIZE 512
|
||||||
|
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
|
||||||
|
tailpos = tail = os_malloc(BEACON_TAIL_BUF_SIZE);
|
||||||
|
if (head == NULL || tail == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to set beacon data");
|
||||||
|
os_free(head);
|
||||||
|
os_free(tail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||||
|
WLAN_FC_STYPE_BEACON);
|
||||||
|
head->duration = host_to_le16(0);
|
||||||
|
os_memset(head->da, 0xff, ETH_ALEN);
|
||||||
|
|
||||||
|
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
|
||||||
|
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
|
||||||
|
head->u.beacon.beacon_int =
|
||||||
|
host_to_le16(hapd->iconf->beacon_int);
|
||||||
|
|
||||||
|
/* hardware or low-level driver will setup seq_ctrl and timestamp */
|
||||||
|
capab_info = hostapd_own_capab_info(hapd, NULL, 0);
|
||||||
|
head->u.beacon.capab_info = host_to_le16(capab_info);
|
||||||
|
pos = &head->u.beacon.variable[0];
|
||||||
|
|
||||||
|
/* SSID */
|
||||||
|
*pos++ = WLAN_EID_SSID;
|
||||||
|
if (hapd->conf->ignore_broadcast_ssid == 2) {
|
||||||
|
/* clear the data, but keep the correct length of the SSID */
|
||||||
|
*pos++ = hapd->conf->ssid.ssid_len;
|
||||||
|
os_memset(pos, 0, hapd->conf->ssid.ssid_len);
|
||||||
|
pos += hapd->conf->ssid.ssid_len;
|
||||||
|
} else if (hapd->conf->ignore_broadcast_ssid) {
|
||||||
|
*pos++ = 0; /* empty SSID */
|
||||||
|
} else {
|
||||||
|
*pos++ = hapd->conf->ssid.ssid_len;
|
||||||
|
os_memcpy(pos, hapd->conf->ssid.ssid,
|
||||||
|
hapd->conf->ssid.ssid_len);
|
||||||
|
pos += hapd->conf->ssid.ssid_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Supported rates */
|
||||||
|
pos = hostapd_eid_supp_rates(hapd, pos);
|
||||||
|
|
||||||
|
/* DS Params */
|
||||||
|
pos = hostapd_eid_ds_params(hapd, pos);
|
||||||
|
|
||||||
|
head_len = pos - (u8 *) head;
|
||||||
|
|
||||||
|
tailpos = hostapd_eid_country(hapd, tailpos,
|
||||||
|
tail + BEACON_TAIL_BUF_SIZE - tailpos);
|
||||||
|
|
||||||
|
tailpos = hostapd_eid_power_constraint(hapd, tailpos);
|
||||||
|
tailpos = hostapd_eid_channel_switch(hapd, tailpos);
|
||||||
|
tailpos = hostapd_eid_tpc_report(hapd, tailpos);
|
||||||
|
|
||||||
|
/* ERP Information element */
|
||||||
|
tailpos = hostapd_eid_erp_info(hapd, tailpos);
|
||||||
|
|
||||||
|
/* Extended supported rates */
|
||||||
|
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
|
||||||
|
|
||||||
|
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
|
||||||
|
tailpos, NULL);
|
||||||
|
|
||||||
|
/* Wi-Fi Wireless Multimedia Extensions */
|
||||||
|
if (hapd->conf->wme_enabled)
|
||||||
|
tailpos = hostapd_eid_wme(hapd, tailpos);
|
||||||
|
|
||||||
|
tail_len = tailpos > tail ? tailpos - tail : 0;
|
||||||
|
|
||||||
|
if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
|
||||||
|
tail, tail_len))
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail");
|
||||||
|
|
||||||
|
os_free(tail);
|
||||||
|
os_free(head);
|
||||||
|
|
||||||
|
if (hostapd_set_cts_protect(hapd, cts_protection))
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
|
||||||
|
"driver");
|
||||||
|
|
||||||
|
if (hapd->iface->current_mode &&
|
||||||
|
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
|
||||||
|
hostapd_set_short_slot_time(hapd,
|
||||||
|
hapd->iface->num_sta_no_short_slot_time
|
||||||
|
> 0 ? 0 : 1))
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
|
||||||
|
"in kernel driver");
|
||||||
|
|
||||||
|
if (hapd->iface->num_sta_no_short_preamble == 0 &&
|
||||||
|
hapd->iconf->preamble == SHORT_PREAMBLE)
|
||||||
|
preamble = SHORT_PREAMBLE;
|
||||||
|
else
|
||||||
|
preamble = LONG_PREAMBLE;
|
||||||
|
if (hostapd_set_preamble(hapd, preamble))
|
||||||
|
wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
|
||||||
|
"driver");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ieee802_11_set_beacons(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < iface->num_bss; i++)
|
||||||
|
ieee802_11_set_beacon(iface->bss[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
24
hostapd/beacon.h
Normal file
24
hostapd/beacon.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
|
||||||
|
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BEACON_H
|
||||||
|
#define BEACON_H
|
||||||
|
|
||||||
|
void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
|
||||||
|
size_t len);
|
||||||
|
void ieee802_11_set_beacon(struct hostapd_data *hapd);
|
||||||
|
void ieee802_11_set_beacons(struct hostapd_iface *iface);
|
||||||
|
|
||||||
|
#endif /* BEACON_H */
|
2238
hostapd/config.c
Normal file
2238
hostapd/config.c
Normal file
File diff suppressed because it is too large
Load diff
358
hostapd/config.h
Normal file
358
hostapd/config.h
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Configuration file
|
||||||
|
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "ip_addr.h"
|
||||||
|
#include "wpa_common.h"
|
||||||
|
|
||||||
|
#ifndef IFNAMSIZ
|
||||||
|
#define IFNAMSIZ 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef u8 macaddr[ETH_ALEN];
|
||||||
|
|
||||||
|
struct hostapd_radius_servers;
|
||||||
|
struct ft_remote_r0kh;
|
||||||
|
struct ft_remote_r1kh;
|
||||||
|
|
||||||
|
#define HOSTAPD_MAX_SSID_LEN 32
|
||||||
|
|
||||||
|
#define NUM_WEP_KEYS 4
|
||||||
|
struct hostapd_wep_keys {
|
||||||
|
u8 idx;
|
||||||
|
u8 *key[NUM_WEP_KEYS];
|
||||||
|
size_t len[NUM_WEP_KEYS];
|
||||||
|
int keys_set;
|
||||||
|
size_t default_len; /* key length used for dynamic key generation */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum hostap_security_policy {
|
||||||
|
SECURITY_PLAINTEXT = 0,
|
||||||
|
SECURITY_STATIC_WEP = 1,
|
||||||
|
SECURITY_IEEE_802_1X = 2,
|
||||||
|
SECURITY_WPA_PSK = 3,
|
||||||
|
SECURITY_WPA = 4
|
||||||
|
} secpolicy;
|
||||||
|
|
||||||
|
struct hostapd_ssid {
|
||||||
|
char ssid[HOSTAPD_MAX_SSID_LEN + 1];
|
||||||
|
size_t ssid_len;
|
||||||
|
int ssid_set;
|
||||||
|
|
||||||
|
char vlan[IFNAMSIZ + 1];
|
||||||
|
secpolicy security_policy;
|
||||||
|
|
||||||
|
struct hostapd_wpa_psk *wpa_psk;
|
||||||
|
char *wpa_passphrase;
|
||||||
|
char *wpa_psk_file;
|
||||||
|
|
||||||
|
struct hostapd_wep_keys wep;
|
||||||
|
|
||||||
|
#define DYNAMIC_VLAN_DISABLED 0
|
||||||
|
#define DYNAMIC_VLAN_OPTIONAL 1
|
||||||
|
#define DYNAMIC_VLAN_REQUIRED 2
|
||||||
|
int dynamic_vlan;
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
char *vlan_tagged_interface;
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
struct hostapd_wep_keys **dyn_vlan_keys;
|
||||||
|
size_t max_dyn_vlan_keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define VLAN_ID_WILDCARD -1
|
||||||
|
|
||||||
|
struct hostapd_vlan {
|
||||||
|
struct hostapd_vlan *next;
|
||||||
|
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
|
||||||
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
int dynamic_vlan;
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
|
||||||
|
#define DVLAN_CLEAN_BR 0x1
|
||||||
|
#define DVLAN_CLEAN_VLAN 0x2
|
||||||
|
#define DVLAN_CLEAN_VLAN_PORT 0x4
|
||||||
|
#define DVLAN_CLEAN_WLAN_PORT 0x8
|
||||||
|
int clean;
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PMK_LEN 32
|
||||||
|
struct hostapd_wpa_psk {
|
||||||
|
struct hostapd_wpa_psk *next;
|
||||||
|
int group;
|
||||||
|
u8 psk[PMK_LEN];
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EAP_USER_MAX_METHODS 8
|
||||||
|
struct hostapd_eap_user {
|
||||||
|
struct hostapd_eap_user *next;
|
||||||
|
u8 *identity;
|
||||||
|
size_t identity_len;
|
||||||
|
struct {
|
||||||
|
int vendor;
|
||||||
|
u32 method;
|
||||||
|
} methods[EAP_USER_MAX_METHODS];
|
||||||
|
u8 *password;
|
||||||
|
size_t password_len;
|
||||||
|
int phase2;
|
||||||
|
int force_version;
|
||||||
|
unsigned int wildcard_prefix:1;
|
||||||
|
unsigned int password_hash:1; /* whether password is hashed with
|
||||||
|
* nt_password_hash() */
|
||||||
|
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define NUM_TX_QUEUES 8
|
||||||
|
|
||||||
|
struct hostapd_tx_queue_params {
|
||||||
|
int aifs;
|
||||||
|
int cwmin;
|
||||||
|
int cwmax;
|
||||||
|
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
|
||||||
|
int configured;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hostapd_wme_ac_params {
|
||||||
|
int cwmin;
|
||||||
|
int cwmax;
|
||||||
|
int aifs;
|
||||||
|
int txopLimit; /* in units of 32us */
|
||||||
|
int admission_control_mandatory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hostapd_bss_config - Per-BSS configuration
|
||||||
|
*/
|
||||||
|
struct hostapd_bss_config {
|
||||||
|
char iface[IFNAMSIZ + 1];
|
||||||
|
char bridge[IFNAMSIZ + 1];
|
||||||
|
|
||||||
|
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
|
||||||
|
|
||||||
|
unsigned int logger_syslog; /* module bitfield */
|
||||||
|
unsigned int logger_stdout; /* module bitfield */
|
||||||
|
|
||||||
|
char *dump_log_name; /* file name for state dump (SIGUSR1) */
|
||||||
|
|
||||||
|
int max_num_sta; /* maximum number of STAs in station table */
|
||||||
|
|
||||||
|
int dtim_period;
|
||||||
|
|
||||||
|
int ieee802_1x; /* use IEEE 802.1X */
|
||||||
|
int eapol_version;
|
||||||
|
int eap_server; /* Use internal EAP server instead of external
|
||||||
|
* RADIUS server */
|
||||||
|
struct hostapd_eap_user *eap_user;
|
||||||
|
char *eap_sim_db;
|
||||||
|
struct hostapd_ip_addr own_ip_addr;
|
||||||
|
char *nas_identifier;
|
||||||
|
struct hostapd_radius_servers *radius;
|
||||||
|
|
||||||
|
struct hostapd_ssid ssid;
|
||||||
|
|
||||||
|
char *eap_req_id_text; /* optional displayable message sent with
|
||||||
|
* EAP Request-Identity */
|
||||||
|
size_t eap_req_id_text_len;
|
||||||
|
int eapol_key_index_workaround;
|
||||||
|
|
||||||
|
size_t default_wep_key_len;
|
||||||
|
int individual_wep_key_len;
|
||||||
|
int wep_rekeying_period;
|
||||||
|
int broadcast_key_idx_min, broadcast_key_idx_max;
|
||||||
|
int eap_reauth_period;
|
||||||
|
|
||||||
|
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
|
||||||
|
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
|
||||||
|
* frames */
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
|
||||||
|
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
|
||||||
|
|
||||||
|
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
|
||||||
|
int wpa_key_mgmt;
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
enum {
|
||||||
|
NO_IEEE80211W = 0,
|
||||||
|
IEEE80211W_OPTIONAL = 1,
|
||||||
|
IEEE80211W_REQUIRED = 2
|
||||||
|
} ieee80211w;
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
int wpa_pairwise;
|
||||||
|
int wpa_group;
|
||||||
|
int wpa_group_rekey;
|
||||||
|
int wpa_strict_rekey;
|
||||||
|
int wpa_gmk_rekey;
|
||||||
|
int rsn_pairwise;
|
||||||
|
int rsn_preauth;
|
||||||
|
char *rsn_preauth_interfaces;
|
||||||
|
int peerkey;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211R
|
||||||
|
/* IEEE 802.11r - Fast BSS Transition */
|
||||||
|
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||||
|
u8 r1_key_holder[FT_R1KH_ID_LEN];
|
||||||
|
u32 r0_key_lifetime;
|
||||||
|
u32 reassociation_deadline;
|
||||||
|
struct ft_remote_r0kh *r0kh_list;
|
||||||
|
struct ft_remote_r1kh *r1kh_list;
|
||||||
|
int pmk_r1_push;
|
||||||
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
|
||||||
|
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||||
|
gid_t ctrl_interface_gid;
|
||||||
|
int ctrl_interface_gid_set;
|
||||||
|
|
||||||
|
char *ca_cert;
|
||||||
|
char *server_cert;
|
||||||
|
char *private_key;
|
||||||
|
char *private_key_passwd;
|
||||||
|
int check_crl;
|
||||||
|
char *dh_file;
|
||||||
|
u8 *pac_opaque_encr_key;
|
||||||
|
char *eap_fast_a_id;
|
||||||
|
int eap_sim_aka_result_ind;
|
||||||
|
|
||||||
|
char *radius_server_clients;
|
||||||
|
int radius_server_auth_port;
|
||||||
|
int radius_server_ipv6;
|
||||||
|
|
||||||
|
char *test_socket; /* UNIX domain socket path for driver_test */
|
||||||
|
|
||||||
|
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
|
||||||
|
* address instead of individual address
|
||||||
|
* (for driver_wired.c).
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ap_max_inactivity;
|
||||||
|
int ignore_broadcast_ssid;
|
||||||
|
|
||||||
|
int wme_enabled;
|
||||||
|
|
||||||
|
struct hostapd_vlan *vlan, *vlan_tail;
|
||||||
|
|
||||||
|
macaddr bssid;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HOSTAPD_MODE_IEEE80211B,
|
||||||
|
HOSTAPD_MODE_IEEE80211G,
|
||||||
|
HOSTAPD_MODE_IEEE80211A,
|
||||||
|
NUM_HOSTAPD_MODES
|
||||||
|
} hostapd_hw_mode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hostapd_config - Per-radio interface configuration
|
||||||
|
*/
|
||||||
|
struct hostapd_config {
|
||||||
|
struct hostapd_bss_config *bss, *last_bss;
|
||||||
|
struct hostapd_radius_servers *radius;
|
||||||
|
size_t num_bss;
|
||||||
|
|
||||||
|
u16 beacon_int;
|
||||||
|
int rts_threshold;
|
||||||
|
int fragm_threshold;
|
||||||
|
u8 send_probe_response;
|
||||||
|
u8 channel;
|
||||||
|
hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||||
|
enum {
|
||||||
|
LONG_PREAMBLE = 0,
|
||||||
|
SHORT_PREAMBLE = 1
|
||||||
|
} preamble;
|
||||||
|
enum {
|
||||||
|
CTS_PROTECTION_AUTOMATIC = 0,
|
||||||
|
CTS_PROTECTION_FORCE_ENABLED = 1,
|
||||||
|
CTS_PROTECTION_FORCE_DISABLED = 2,
|
||||||
|
CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
|
||||||
|
} cts_protection_type;
|
||||||
|
|
||||||
|
int *supported_rates;
|
||||||
|
int *basic_rates;
|
||||||
|
|
||||||
|
const struct wpa_driver_ops *driver;
|
||||||
|
|
||||||
|
int passive_scan_interval; /* seconds, 0 = disabled */
|
||||||
|
int passive_scan_listen; /* usec */
|
||||||
|
int passive_scan_mode;
|
||||||
|
int ap_table_max_size;
|
||||||
|
int ap_table_expiration_time;
|
||||||
|
|
||||||
|
char country[3]; /* first two octets: country code as described in
|
||||||
|
* ISO/IEC 3166-1. Third octet:
|
||||||
|
* ' ' (ascii 32): all environments
|
||||||
|
* 'O': Outdoor environemnt only
|
||||||
|
* 'I': Indoor environment only
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ieee80211d;
|
||||||
|
unsigned int ieee80211h; /* Enable/Disable 80211h */
|
||||||
|
|
||||||
|
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WME AC parameters, in same order as 802.1D, i.e.
|
||||||
|
* 0 = BE (best effort)
|
||||||
|
* 1 = BK (background)
|
||||||
|
* 2 = VI (video)
|
||||||
|
* 3 = VO (voice)
|
||||||
|
*/
|
||||||
|
struct hostapd_wme_ac_params wme_ac_params[4];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
|
||||||
|
INTERNAL_BRIDGE_DISABLED = 0,
|
||||||
|
INTERNAL_BRIDGE_ENABLED = 1
|
||||||
|
} bridge_packets;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_mac_comp(const void *a, const void *b);
|
||||||
|
int hostapd_mac_comp_empty(const void *a);
|
||||||
|
struct hostapd_config * hostapd_config_read(const char *fname);
|
||||||
|
void hostapd_config_free(struct hostapd_config *conf);
|
||||||
|
int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr);
|
||||||
|
int hostapd_rate_found(int *list, int rate);
|
||||||
|
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
|
||||||
|
struct hostapd_wep_keys *b);
|
||||||
|
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||||
|
const u8 *addr, const u8 *prev_psk);
|
||||||
|
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
|
||||||
|
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
|
||||||
|
int vlan_id);
|
||||||
|
const struct hostapd_eap_user *
|
||||||
|
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
|
||||||
|
size_t identity_len, int phase2);
|
||||||
|
|
||||||
|
#endif /* CONFIG_H */
|
500
hostapd/ctrl_iface.c
Normal file
500
hostapd/ctrl_iface.c
Normal file
|
@ -0,0 +1,500 @@
|
||||||
|
/*
|
||||||
|
* hostapd / UNIX domain socket -based control interface
|
||||||
|
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
|
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "radius/radius_client.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "ctrl_iface.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "accounting.h"
|
||||||
|
|
||||||
|
|
||||||
|
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 = os_zalloc(sizeof(*dst));
|
||||||
|
if (dst == NULL)
|
||||||
|
return -1;
|
||||||
|
os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
|
||||||
|
dst->addrlen = fromlen;
|
||||||
|
dst->debug_level = MSG_INFO;
|
||||||
|
dst->next = hapd->ctrl_dst;
|
||||||
|
hapd->ctrl_dst = dst;
|
||||||
|
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
|
||||||
|
(u8 *) from->sun_path, fromlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
|
||||||
|
struct sockaddr_un *from,
|
||||||
|
socklen_t fromlen)
|
||||||
|
{
|
||||||
|
struct wpa_ctrl_dst *dst, *prev = NULL;
|
||||||
|
|
||||||
|
dst = hapd->ctrl_dst;
|
||||||
|
while (dst) {
|
||||||
|
if (fromlen == dst->addrlen &&
|
||||||
|
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
|
||||||
|
0) {
|
||||||
|
if (prev == NULL)
|
||||||
|
hapd->ctrl_dst = dst->next;
|
||||||
|
else
|
||||||
|
prev->next = dst->next;
|
||||||
|
os_free(dst);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
|
||||||
|
(u8 *) from->sun_path, fromlen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prev = dst;
|
||||||
|
dst = dst->next;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
|
||||||
|
struct sockaddr_un *from,
|
||||||
|
socklen_t fromlen,
|
||||||
|
char *level)
|
||||||
|
{
|
||||||
|
struct wpa_ctrl_dst *dst;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
|
||||||
|
|
||||||
|
dst = hapd->ctrl_dst;
|
||||||
|
while (dst) {
|
||||||
|
if (fromlen == dst->addrlen &&
|
||||||
|
os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
|
||||||
|
0) {
|
||||||
|
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
|
||||||
|
"level", (u8 *) from->sun_path, fromlen);
|
||||||
|
dst->debug_level = atoi(level);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dst = dst->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta,
|
||||||
|
char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
int len, res, ret;
|
||||||
|
|
||||||
|
if (sta == NULL) {
|
||||||
|
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||||
|
if (ret < 0 || (size_t) ret >= buflen)
|
||||||
|
return 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
if (ret < 0 || (size_t) ret >= buflen - len)
|
||||||
|
return len;
|
||||||
|
len += ret;
|
||||||
|
|
||||||
|
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||||
|
if (res >= 0)
|
||||||
|
len += res;
|
||||||
|
res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
|
||||||
|
if (res >= 0)
|
||||||
|
len += res;
|
||||||
|
res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||||
|
if (res >= 0)
|
||||||
|
len += res;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
|
||||||
|
char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
|
||||||
|
const char *txtaddr,
|
||||||
|
char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (hwaddr_aton(txtaddr, addr)) {
|
||||||
|
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||||
|
if (ret < 0 || (size_t) ret >= buflen)
|
||||||
|
return 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
|
||||||
|
buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
|
||||||
|
const char *txtaddr,
|
||||||
|
char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
struct sta_info *sta;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (hwaddr_aton(txtaddr, addr) ||
|
||||||
|
(sta = ap_get_sta(hapd, addr)) == NULL) {
|
||||||
|
ret = os_snprintf(buf, buflen, "FAIL\n");
|
||||||
|
if (ret < 0 || (size_t) ret >= buflen)
|
||||||
|
return 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
|
||||||
|
const char *txtaddr)
|
||||||
|
{
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
|
||||||
|
|
||||||
|
if (hwaddr_aton(txtaddr, addr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, addr);
|
||||||
|
if (sta)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
|
||||||
|
"notification", MAC2STR(addr));
|
||||||
|
sta = ap_sta_add(hapd, addr);
|
||||||
|
if (sta == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hostapd_new_assoc_sta(hapd, sta, 0);
|
||||||
|
accounting_sta_get_id(hapd, sta);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||||
|
void *sock_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
char buf[256];
|
||||||
|
int res;
|
||||||
|
struct sockaddr_un from;
|
||||||
|
socklen_t fromlen = sizeof(from);
|
||||||
|
char *reply;
|
||||||
|
const int reply_size = 4096;
|
||||||
|
int reply_len;
|
||||||
|
|
||||||
|
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
|
||||||
|
(struct sockaddr *) &from, &fromlen);
|
||||||
|
if (res < 0) {
|
||||||
|
perror("recvfrom(ctrl_iface)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf[res] = '\0';
|
||||||
|
wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
|
||||||
|
|
||||||
|
reply = os_malloc(reply_size);
|
||||||
|
if (reply == NULL) {
|
||||||
|
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
|
||||||
|
fromlen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memcpy(reply, "OK\n", 3);
|
||||||
|
reply_len = 3;
|
||||||
|
|
||||||
|
if (os_strcmp(buf, "PING") == 0) {
|
||||||
|
os_memcpy(reply, "PONG\n", 5);
|
||||||
|
reply_len = 5;
|
||||||
|
} else if (os_strcmp(buf, "MIB") == 0) {
|
||||||
|
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
|
||||||
|
if (reply_len >= 0) {
|
||||||
|
res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
|
||||||
|
reply_size - reply_len);
|
||||||
|
if (res < 0)
|
||||||
|
reply_len = -1;
|
||||||
|
else
|
||||||
|
reply_len += res;
|
||||||
|
}
|
||||||
|
if (reply_len >= 0) {
|
||||||
|
res = ieee802_1x_get_mib(hapd, reply + reply_len,
|
||||||
|
reply_size - reply_len);
|
||||||
|
if (res < 0)
|
||||||
|
reply_len = -1;
|
||||||
|
else
|
||||||
|
reply_len += res;
|
||||||
|
}
|
||||||
|
if (reply_len >= 0) {
|
||||||
|
res = radius_client_get_mib(hapd->radius,
|
||||||
|
reply + reply_len,
|
||||||
|
reply_size - reply_len);
|
||||||
|
if (res < 0)
|
||||||
|
reply_len = -1;
|
||||||
|
else
|
||||||
|
reply_len += res;
|
||||||
|
}
|
||||||
|
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
|
||||||
|
reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
|
||||||
|
reply_size);
|
||||||
|
} else if (os_strncmp(buf, "STA ", 4) == 0) {
|
||||||
|
reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
|
||||||
|
reply_size);
|
||||||
|
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
|
||||||
|
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
|
||||||
|
reply_size);
|
||||||
|
} else if (os_strcmp(buf, "ATTACH") == 0) {
|
||||||
|
if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
|
||||||
|
reply_len = -1;
|
||||||
|
} else if (os_strcmp(buf, "DETACH") == 0) {
|
||||||
|
if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
|
||||||
|
reply_len = -1;
|
||||||
|
} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
|
||||||
|
if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
|
||||||
|
buf + 6))
|
||||||
|
reply_len = -1;
|
||||||
|
} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
|
||||||
|
if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
|
||||||
|
reply_len = -1;
|
||||||
|
} else {
|
||||||
|
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
||||||
|
reply_len = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply_len < 0) {
|
||||||
|
os_memcpy(reply, "FAIL\n", 5);
|
||||||
|
reply_len = 5;
|
||||||
|
}
|
||||||
|
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
|
||||||
|
os_free(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (hapd->conf->ctrl_interface == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
len = os_strlen(hapd->conf->ctrl_interface) +
|
||||||
|
os_strlen(hapd->conf->iface) + 2;
|
||||||
|
buf = os_malloc(len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
os_snprintf(buf, len, "%s/%s",
|
||||||
|
hapd->conf->ctrl_interface, hapd->conf->iface);
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
int s = -1;
|
||||||
|
char *fname = NULL;
|
||||||
|
|
||||||
|
hapd->ctrl_sock = -1;
|
||||||
|
|
||||||
|
if (hapd->conf->ctrl_interface == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
|
||||||
|
if (errno == EEXIST) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Using existing control "
|
||||||
|
"interface directory.");
|
||||||
|
} else {
|
||||||
|
perror("mkdir[ctrl_interface]");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->conf->ctrl_interface_gid_set &&
|
||||||
|
chown(hapd->conf->ctrl_interface, 0,
|
||||||
|
hapd->conf->ctrl_interface_gid) < 0) {
|
||||||
|
perror("chown[ctrl_interface]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
|
||||||
|
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||||
|
if (s < 0) {
|
||||||
|
perror("socket(PF_UNIX)");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
fname = hostapd_ctrl_iface_path(hapd);
|
||||||
|
if (fname == NULL)
|
||||||
|
goto fail;
|
||||||
|
os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
|
||||||
|
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||||
|
perror("bind(PF_UNIX)");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->conf->ctrl_interface_gid_set &&
|
||||||
|
chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
|
||||||
|
perror("chown[ctrl_interface/ifname]");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
|
||||||
|
perror("chmod[ctrl_interface/ifname]");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
os_free(fname);
|
||||||
|
|
||||||
|
hapd->ctrl_sock = s;
|
||||||
|
eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (s >= 0)
|
||||||
|
close(s);
|
||||||
|
if (fname) {
|
||||||
|
unlink(fname);
|
||||||
|
os_free(fname);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct wpa_ctrl_dst *dst, *prev;
|
||||||
|
|
||||||
|
if (hapd->ctrl_sock > -1) {
|
||||||
|
char *fname;
|
||||||
|
eloop_unregister_read_sock(hapd->ctrl_sock);
|
||||||
|
close(hapd->ctrl_sock);
|
||||||
|
hapd->ctrl_sock = -1;
|
||||||
|
fname = hostapd_ctrl_iface_path(hapd);
|
||||||
|
if (fname)
|
||||||
|
unlink(fname);
|
||||||
|
os_free(fname);
|
||||||
|
|
||||||
|
if (hapd->conf->ctrl_interface &&
|
||||||
|
rmdir(hapd->conf->ctrl_interface) < 0) {
|
||||||
|
if (errno == ENOTEMPTY) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Control interface "
|
||||||
|
"directory not empty - leaving it "
|
||||||
|
"behind");
|
||||||
|
} else {
|
||||||
|
perror("rmdir[ctrl_interface]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = hapd->ctrl_dst;
|
||||||
|
while (dst) {
|
||||||
|
prev = dst;
|
||||||
|
dst = dst->next;
|
||||||
|
os_free(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
|
||||||
|
io[0].iov_base = levelstr;
|
||||||
|
io[0].iov_len = os_strlen(levelstr);
|
||||||
|
io[1].iov_base = buf;
|
||||||
|
io[1].iov_len = len;
|
||||||
|
os_memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = io;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
while (dst) {
|
||||||
|
next = dst->next;
|
||||||
|
if (level >= dst->debug_level) {
|
||||||
|
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
|
||||||
|
(u8 *) dst->addr.sun_path, dst->addrlen);
|
||||||
|
msg.msg_name = &dst->addr;
|
||||||
|
msg.msg_namelen = dst->addrlen;
|
||||||
|
if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
|
||||||
|
fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
|
||||||
|
idx);
|
||||||
|
perror("sendmsg");
|
||||||
|
dst->errors++;
|
||||||
|
if (dst->errors > 10) {
|
||||||
|
hostapd_ctrl_iface_detach(
|
||||||
|
hapd, &dst->addr,
|
||||||
|
dst->addrlen);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
dst->errors = 0;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
dst = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
23
hostapd/ctrl_iface.h
Normal file
23
hostapd/ctrl_iface.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* hostapd / UNIX domain socket -based control interface
|
||||||
|
* Copyright (c) 2004, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CTRL_IFACE_H
|
||||||
|
#define CTRL_IFACE_H
|
||||||
|
|
||||||
|
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
|
||||||
|
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
|
||||||
|
void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
|
||||||
|
char *buf, size_t len);
|
||||||
|
|
||||||
|
#endif /* CTRL_IFACE_H */
|
119
hostapd/defconfig
Normal file
119
hostapd/defconfig
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
# 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 drivers using the nl80211 kernel interface
|
||||||
|
#CONFIG_DRIVER_NL80211=y
|
||||||
|
# driver_nl80211.c requires a rather new libnl, probably not
|
||||||
|
# shipped with your distribution yet
|
||||||
|
#LIBNL=/usr/src/libnl
|
||||||
|
#CFLAGS += -I$(LIBNL)/include
|
||||||
|
#LIBS += -L$(LIBNL)/lib
|
||||||
|
|
||||||
|
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
|
||||||
|
#CONFIG_DRIVER_BSD=y
|
||||||
|
#CFLAGS += -I/usr/local/include
|
||||||
|
#LIBS += -L/usr/local/lib
|
||||||
|
|
||||||
|
# IEEE 802.11F/IAPP
|
||||||
|
CONFIG_IAPP=y
|
||||||
|
|
||||||
|
# WPA2/IEEE 802.11i RSN pre-authentication
|
||||||
|
CONFIG_RSN_PREAUTH=y
|
||||||
|
|
||||||
|
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
|
||||||
|
CONFIG_PEERKEY=y
|
||||||
|
|
||||||
|
# IEEE 802.11w (management frame protection)
|
||||||
|
# This version is an experimental implementation based on IEEE 802.11w/D1.0
|
||||||
|
# draft and is subject to change since the standard has not yet been finalized.
|
||||||
|
# Driver support is also needed for IEEE 802.11w.
|
||||||
|
#CONFIG_IEEE80211W=y
|
||||||
|
|
||||||
|
# Integrated EAP server
|
||||||
|
CONFIG_EAP=y
|
||||||
|
|
||||||
|
# EAP-MD5 for the integrated EAP server
|
||||||
|
CONFIG_EAP_MD5=y
|
||||||
|
|
||||||
|
# EAP-TLS for the integrated EAP server
|
||||||
|
CONFIG_EAP_TLS=y
|
||||||
|
|
||||||
|
# EAP-MSCHAPv2 for the integrated EAP server
|
||||||
|
CONFIG_EAP_MSCHAPV2=y
|
||||||
|
|
||||||
|
# EAP-PEAP for the integrated EAP server
|
||||||
|
CONFIG_EAP_PEAP=y
|
||||||
|
|
||||||
|
# EAP-GTC for the integrated EAP server
|
||||||
|
CONFIG_EAP_GTC=y
|
||||||
|
|
||||||
|
# EAP-TTLS for the integrated EAP server
|
||||||
|
CONFIG_EAP_TTLS=y
|
||||||
|
|
||||||
|
# EAP-SIM for the integrated EAP server
|
||||||
|
#CONFIG_EAP_SIM=y
|
||||||
|
|
||||||
|
# EAP-AKA for the integrated EAP server
|
||||||
|
#CONFIG_EAP_AKA=y
|
||||||
|
|
||||||
|
# EAP-PAX for the integrated EAP server
|
||||||
|
#CONFIG_EAP_PAX=y
|
||||||
|
|
||||||
|
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
|
||||||
|
#CONFIG_EAP_PSK=y
|
||||||
|
|
||||||
|
# EAP-SAKE for the integrated EAP server
|
||||||
|
#CONFIG_EAP_SAKE=y
|
||||||
|
|
||||||
|
# EAP-GPSK for the integrated EAP server
|
||||||
|
#CONFIG_EAP_GPSK=y
|
||||||
|
# Include support for optional SHA256 cipher suite in EAP-GPSK
|
||||||
|
#CONFIG_EAP_GPSK_SHA256=y
|
||||||
|
|
||||||
|
# EAP-FAST for the integrated EAP server
|
||||||
|
# Note: Default OpenSSL package does not include support for all the
|
||||||
|
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
|
||||||
|
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
|
||||||
|
# to add the needed functions.
|
||||||
|
#CONFIG_EAP_FAST=y
|
||||||
|
|
||||||
|
# EAP-IKEv2
|
||||||
|
#CONFIG_EAP_IKEV2=y
|
||||||
|
|
||||||
|
# PKCS#12 (PFX) support (used to read private key and certificate file from
|
||||||
|
# a file that usually has extension .p12 or .pfx)
|
||||||
|
CONFIG_PKCS12=y
|
||||||
|
|
||||||
|
# RADIUS authentication server. This provides access to the integrated EAP
|
||||||
|
# server from external hosts using RADIUS.
|
||||||
|
#CONFIG_RADIUS_SERVER=y
|
||||||
|
|
||||||
|
# Build IPv6 support for RADIUS operations
|
||||||
|
CONFIG_IPV6=y
|
||||||
|
|
||||||
|
# IEEE 802.11r/D4.1 (Fast BSS Transition)
|
||||||
|
# This enables an experimental implementation of a draft version of
|
||||||
|
# IEEE 802.11r. This draft is still subject to change, so it should be noted
|
||||||
|
# that this version may not comply with the final standard.
|
||||||
|
#CONFIG_IEEE80211R=y
|
219
hostapd/developer.txt
Normal file
219
hostapd/developer.txt
Normal file
|
@ -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]
|
4
hostapd/doc/.gitignore
vendored
Normal file
4
hostapd/doc/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
html
|
||||||
|
latex
|
||||||
|
hostapd.eps
|
||||||
|
hostapd.png
|
5
hostapd/doc/code_structure.doxygen
Normal file
5
hostapd/doc/code_structure.doxygen
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
\page code_structure Structure of the source code
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
66
hostapd/doc/ctrl_iface.doxygen
Normal file
66
hostapd/doc/ctrl_iface.doxygen
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
\page ctrl_iface_page Control interface
|
||||||
|
|
||||||
|
hostapd implements a control interface that can be used by
|
||||||
|
external programs to control the operations of the hostapd
|
||||||
|
daemon and to get status information and event notifications. There is
|
||||||
|
a small C library, in a form of a single C file, wpa_ctrl.c, that
|
||||||
|
provides helper functions to facilitate the use of the control
|
||||||
|
interface. External programs can link this file into them and then use
|
||||||
|
the library functions documented in wpa_ctrl.h to interact with
|
||||||
|
%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
|
||||||
|
is an example program using this library.
|
||||||
|
|
||||||
|
There are multiple mechanisms for inter-process communication. For
|
||||||
|
example, Linux version of hostapd is using UNIX domain sockets for the
|
||||||
|
control interface. The use of the functions defined in wpa_ctrl.h can
|
||||||
|
be used to hide the details of the used IPC from external programs.
|
||||||
|
|
||||||
|
|
||||||
|
\section using_ctrl_iface Using the control interface
|
||||||
|
|
||||||
|
External programs, e.g., a GUI or a configuration utility, that need to
|
||||||
|
communicate with hostapd should link in wpa_ctrl.c. This
|
||||||
|
allows them to use helper functions to open connection to the control
|
||||||
|
interface with wpa_ctrl_open() and to send commands with
|
||||||
|
wpa_ctrl_request().
|
||||||
|
|
||||||
|
hostapd uses the control interface for two types of communication:
|
||||||
|
commands and unsolicited event messages. Commands are a pair of
|
||||||
|
messages, a request from the external program and a response from
|
||||||
|
hostapd. These can be executed using wpa_ctrl_request().
|
||||||
|
Unsolicited event messages are sent by hostapd to the control
|
||||||
|
interface connection without specific request from the external program
|
||||||
|
for receiving each message. However, the external program needs to
|
||||||
|
attach to the control interface with wpa_ctrl_attach() to receive these
|
||||||
|
unsolicited messages.
|
||||||
|
|
||||||
|
If the control interface connection is used both for commands and
|
||||||
|
unsolicited event messages, there is potential for receiving an
|
||||||
|
unsolicited message between the command request and response.
|
||||||
|
wpa_ctrl_request() caller will need to supply a callback, msg_cb,
|
||||||
|
for processing these messages. Often it is easier to open two
|
||||||
|
control interface connections by calling wpa_ctrl_open() twice and
|
||||||
|
then use one of the connections for commands and the other one for
|
||||||
|
unsolicited messages. This way command request/response pairs will
|
||||||
|
not be broken by unsolicited messages. wpa_cli is an example of how
|
||||||
|
to use only one connection for both purposes and wpa_gui demonstrates
|
||||||
|
how to use two separate connections.
|
||||||
|
|
||||||
|
Once the control interface connection is not needed anymore, it should
|
||||||
|
be closed by calling wpa_ctrl_close(). If the connection was used for
|
||||||
|
unsolicited event messages, it should be first detached by calling
|
||||||
|
wpa_ctrl_detach().
|
||||||
|
|
||||||
|
|
||||||
|
\section ctrl_iface_cmds Control interface commands
|
||||||
|
|
||||||
|
Following commands can be used with wpa_ctrl_request():
|
||||||
|
|
||||||
|
\subsection ctrl_iface_PING PING
|
||||||
|
|
||||||
|
This command can be used to test whether hostapd is replying
|
||||||
|
to the control interface commands. The expected reply is \c PONG if the
|
||||||
|
connection is open and hostapd is processing commands.
|
||||||
|
|
||||||
|
*/
|
233
hostapd/doc/doxygen.fast
Normal file
233
hostapd/doc/doxygen.fast
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
# Doxyfile 1.4.4
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Project related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
PROJECT_NAME = hostapd
|
||||||
|
PROJECT_NUMBER = 0.5.x
|
||||||
|
OUTPUT_DIRECTORY = doc
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
USE_WINDOWS_ENCODING = NO
|
||||||
|
BRIEF_MEMBER_DESC = YES
|
||||||
|
REPEAT_BRIEF = YES
|
||||||
|
ABBREVIATE_BRIEF = "The $name class" \
|
||||||
|
"The $name widget" \
|
||||||
|
"The $name file" \
|
||||||
|
is \
|
||||||
|
provides \
|
||||||
|
specifies \
|
||||||
|
contains \
|
||||||
|
represents \
|
||||||
|
a \
|
||||||
|
an \
|
||||||
|
the
|
||||||
|
ALWAYS_DETAILED_SEC = NO
|
||||||
|
INLINE_INHERITED_MEMB = NO
|
||||||
|
FULL_PATH_NAMES = YES
|
||||||
|
STRIP_FROM_PATH =
|
||||||
|
STRIP_FROM_INC_PATH =
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
JAVADOC_AUTOBRIEF = NO
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
DETAILS_AT_TOP = NO
|
||||||
|
INHERIT_DOCS = YES
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
SEPARATE_MEMBER_PAGES = NO
|
||||||
|
TAB_SIZE = 8
|
||||||
|
ALIASES =
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
SUBGROUPING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Build related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
EXTRACT_ALL = NO
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
EXTRACT_LOCAL_METHODS = NO
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
SHOW_INCLUDE_FILES = YES
|
||||||
|
INLINE_INFO = YES
|
||||||
|
SORT_MEMBER_DOCS = YES
|
||||||
|
SORT_BRIEF_DOCS = NO
|
||||||
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
GENERATE_TODOLIST = YES
|
||||||
|
GENERATE_TESTLIST = YES
|
||||||
|
GENERATE_BUGLIST = YES
|
||||||
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
SHOW_USED_FILES = YES
|
||||||
|
SHOW_DIRECTORIES = NO
|
||||||
|
FILE_VERSION_FILTER =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to warning and progress messages
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
QUIET = NO
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
WARN_NO_PARAMDOC = YES
|
||||||
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
|
WARN_LOGFILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the input files
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
INPUT = . \
|
||||||
|
../wpa_supplicant/eap_sim_common.c \
|
||||||
|
../wpa_supplicant/eap_sim_common.h
|
||||||
|
FILE_PATTERNS = *.c *.h *.doxygen
|
||||||
|
RECURSIVE = YES
|
||||||
|
EXCLUDE =
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
EXCLUDE_PATTERNS =
|
||||||
|
EXAMPLE_PATH =
|
||||||
|
EXAMPLE_PATTERNS = *
|
||||||
|
EXAMPLE_RECURSIVE = NO
|
||||||
|
IMAGE_PATH = doc
|
||||||
|
INPUT_FILTER = doc/kerneldoc2doxygen.pl
|
||||||
|
FILTER_PATTERNS =
|
||||||
|
FILTER_SOURCE_FILES = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to source browsing
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SOURCE_BROWSER = YES
|
||||||
|
INLINE_SOURCES = NO
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
|
REFERENCED_BY_RELATION = NO
|
||||||
|
REFERENCES_RELATION = NO
|
||||||
|
VERBATIM_HEADERS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the alphabetical class index
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ALPHABETICAL_INDEX = YES
|
||||||
|
COLS_IN_ALPHA_INDEX = 3
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
HTML_OUTPUT = html
|
||||||
|
HTML_FILE_EXTENSION = .html
|
||||||
|
HTML_HEADER =
|
||||||
|
HTML_FOOTER =
|
||||||
|
HTML_STYLESHEET =
|
||||||
|
HTML_ALIGN_MEMBERS = YES
|
||||||
|
GENERATE_HTMLHELP = NO
|
||||||
|
CHM_FILE =
|
||||||
|
HHC_LOCATION =
|
||||||
|
GENERATE_CHI = NO
|
||||||
|
BINARY_TOC = NO
|
||||||
|
TOC_EXPAND = NO
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
PAPER_TYPE = a4wide
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
LATEX_HEADER =
|
||||||
|
PDF_HYPERLINKS = YES
|
||||||
|
USE_PDFLATEX = YES
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
MAN_LINKS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_XML = NO
|
||||||
|
XML_OUTPUT = xml
|
||||||
|
XML_SCHEMA =
|
||||||
|
XML_DTD =
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options for the AutoGen Definitions output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the Perl module output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the preprocessor
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ENABLE_PREPROCESSING = YES
|
||||||
|
MACRO_EXPANSION = NO
|
||||||
|
EXPAND_ONLY_PREDEF = NO
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
INCLUDE_PATH =
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
TAGFILES =
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
CLASS_DIAGRAMS = NO
|
||||||
|
HIDE_UNDOC_RELATIONS = YES
|
||||||
|
HAVE_DOT = NO
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
COLLABORATION_GRAPH = YES
|
||||||
|
GROUP_GRAPHS = YES
|
||||||
|
UML_LOOK = NO
|
||||||
|
TEMPLATE_RELATIONS = NO
|
||||||
|
INCLUDE_GRAPH = YES
|
||||||
|
INCLUDED_BY_GRAPH = YES
|
||||||
|
CALL_GRAPH = YES
|
||||||
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
DIRECTORY_GRAPH = NO
|
||||||
|
DOT_IMAGE_FORMAT = png
|
||||||
|
DOT_PATH =
|
||||||
|
DOTFILE_DIRS =
|
||||||
|
MAX_DOT_GRAPH_WIDTH = 1024
|
||||||
|
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 1000
|
||||||
|
DOT_TRANSPARENT = NO
|
||||||
|
DOT_MULTI_TARGETS = NO
|
||||||
|
GENERATE_LEGEND = YES
|
||||||
|
DOT_CLEANUP = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to the search engine
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SEARCHENGINE = NO
|
230
hostapd/doc/doxygen.full
Normal file
230
hostapd/doc/doxygen.full
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
# Doxyfile 1.4.1
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Project related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
PROJECT_NAME = hostapd
|
||||||
|
PROJECT_NUMBER = 0.5.x
|
||||||
|
OUTPUT_DIRECTORY = doc
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
USE_WINDOWS_ENCODING = NO
|
||||||
|
BRIEF_MEMBER_DESC = YES
|
||||||
|
REPEAT_BRIEF = YES
|
||||||
|
ABBREVIATE_BRIEF = "The $name class" \
|
||||||
|
"The $name widget" \
|
||||||
|
"The $name file" \
|
||||||
|
is \
|
||||||
|
provides \
|
||||||
|
specifies \
|
||||||
|
contains \
|
||||||
|
represents \
|
||||||
|
a \
|
||||||
|
an \
|
||||||
|
the
|
||||||
|
ALWAYS_DETAILED_SEC = NO
|
||||||
|
INLINE_INHERITED_MEMB = NO
|
||||||
|
FULL_PATH_NAMES = YES
|
||||||
|
STRIP_FROM_PATH =
|
||||||
|
STRIP_FROM_INC_PATH =
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
JAVADOC_AUTOBRIEF = NO
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
DETAILS_AT_TOP = NO
|
||||||
|
INHERIT_DOCS = YES
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
TAB_SIZE = 8
|
||||||
|
ALIASES =
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
SUBGROUPING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Build related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
EXTRACT_ALL = NO
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
EXTRACT_LOCAL_METHODS = NO
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
SHOW_INCLUDE_FILES = YES
|
||||||
|
INLINE_INFO = YES
|
||||||
|
SORT_MEMBER_DOCS = YES
|
||||||
|
SORT_BRIEF_DOCS = NO
|
||||||
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
GENERATE_TODOLIST = YES
|
||||||
|
GENERATE_TESTLIST = YES
|
||||||
|
GENERATE_BUGLIST = YES
|
||||||
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
SHOW_USED_FILES = YES
|
||||||
|
SHOW_DIRECTORIES = NO
|
||||||
|
FILE_VERSION_FILTER =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to warning and progress messages
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
QUIET = NO
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
WARN_NO_PARAMDOC = YES
|
||||||
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
|
WARN_LOGFILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the input files
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
INPUT = .
|
||||||
|
FILE_PATTERNS = *.c *.h *.doxygen
|
||||||
|
RECURSIVE = YES
|
||||||
|
EXCLUDE =
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
EXCLUDE_PATTERNS =
|
||||||
|
EXAMPLE_PATH =
|
||||||
|
EXAMPLE_PATTERNS = *
|
||||||
|
EXAMPLE_RECURSIVE = NO
|
||||||
|
IMAGE_PATH = doc
|
||||||
|
INPUT_FILTER = kerneldoc2doxygen.pl
|
||||||
|
FILTER_PATTERNS =
|
||||||
|
FILTER_SOURCE_FILES = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to source browsing
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SOURCE_BROWSER = YES
|
||||||
|
INLINE_SOURCES = NO
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
|
REFERENCED_BY_RELATION = NO
|
||||||
|
REFERENCES_RELATION = NO
|
||||||
|
VERBATIM_HEADERS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the alphabetical class index
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ALPHABETICAL_INDEX = YES
|
||||||
|
COLS_IN_ALPHA_INDEX = 3
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
HTML_OUTPUT = html
|
||||||
|
HTML_FILE_EXTENSION = .html
|
||||||
|
HTML_HEADER =
|
||||||
|
HTML_FOOTER =
|
||||||
|
HTML_STYLESHEET =
|
||||||
|
HTML_ALIGN_MEMBERS = YES
|
||||||
|
GENERATE_HTMLHELP = NO
|
||||||
|
CHM_FILE =
|
||||||
|
HHC_LOCATION =
|
||||||
|
GENERATE_CHI = NO
|
||||||
|
BINARY_TOC = NO
|
||||||
|
TOC_EXPAND = NO
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_LATEX = YES
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
PAPER_TYPE = a4wide
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
LATEX_HEADER =
|
||||||
|
PDF_HYPERLINKS = YES
|
||||||
|
USE_PDFLATEX = YES
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
MAN_LINKS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_XML = NO
|
||||||
|
XML_OUTPUT = xml
|
||||||
|
XML_SCHEMA =
|
||||||
|
XML_DTD =
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options for the AutoGen Definitions output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the Perl module output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the preprocessor
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ENABLE_PREPROCESSING = YES
|
||||||
|
MACRO_EXPANSION = NO
|
||||||
|
EXPAND_ONLY_PREDEF = NO
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
INCLUDE_PATH =
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
TAGFILES =
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
CLASS_DIAGRAMS = NO
|
||||||
|
HIDE_UNDOC_RELATIONS = YES
|
||||||
|
HAVE_DOT = YES
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
COLLABORATION_GRAPH = YES
|
||||||
|
GROUP_GRAPHS = YES
|
||||||
|
UML_LOOK = NO
|
||||||
|
TEMPLATE_RELATIONS = NO
|
||||||
|
INCLUDE_GRAPH = YES
|
||||||
|
INCLUDED_BY_GRAPH = YES
|
||||||
|
CALL_GRAPH = YES
|
||||||
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
DIRECTORY_GRAPH = NO
|
||||||
|
DOT_IMAGE_FORMAT = png
|
||||||
|
DOT_PATH =
|
||||||
|
DOTFILE_DIRS =
|
||||||
|
MAX_DOT_GRAPH_WIDTH = 1024
|
||||||
|
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 1000
|
||||||
|
DOT_TRANSPARENT = NO
|
||||||
|
DOT_MULTI_TARGETS = NO
|
||||||
|
GENERATE_LEGEND = YES
|
||||||
|
DOT_CLEANUP = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to the search engine
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SEARCHENGINE = YES
|
20
hostapd/doc/driver_wrapper.doxygen
Normal file
20
hostapd/doc/driver_wrapper.doxygen
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
|
||||||
|
|
||||||
|
All hardware and driver dependent functionality is in separate C files
|
||||||
|
that implement defined wrapper functions. Other parts
|
||||||
|
of the hostapd are designed to be hardware, driver, and operating
|
||||||
|
system independent.
|
||||||
|
|
||||||
|
Driver wrappers need to implement whatever calls are used in the
|
||||||
|
target operating system/driver for controlling wireless LAN
|
||||||
|
devices. As an example, in case of Linux, these are mostly some glue
|
||||||
|
code and ioctl() calls and netlink message parsing for Linux Wireless
|
||||||
|
Extensions (WE). Since features required for WPA were added only recently to
|
||||||
|
Linux Wireless Extensions (in version 18), some driver specific code is used
|
||||||
|
in number of driver interface implementations. These driver dependent parts
|
||||||
|
can be replaced with generic code in driver_wext.c once the target driver
|
||||||
|
includes full support for WE-18. After that, all Linux drivers, at
|
||||||
|
least in theory, could use the same driver wrapper code.
|
||||||
|
|
||||||
|
*/
|
56
hostapd/doc/eap.doxygen
Normal file
56
hostapd/doc/eap.doxygen
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
\page eap_module EAP server implementation
|
||||||
|
|
||||||
|
Extensible Authentication Protocol (EAP) is an authentication framework
|
||||||
|
defined in RFC 3748. hostapd uses a separate code module for EAP server
|
||||||
|
implementation. This module was designed to use only a minimal set of
|
||||||
|
direct function calls (mainly, to debug/event functions) in order for
|
||||||
|
it to be usable in other programs. The design of the EAP
|
||||||
|
implementation is based loosely on RFC 4137. The state machine is
|
||||||
|
defined in this RFC and so is the interface between the server state
|
||||||
|
machine and methods. As such, this RFC provides useful information for
|
||||||
|
understanding the EAP server implementation in hostapd.
|
||||||
|
|
||||||
|
Some of the terminology used in EAP state machine is referring to
|
||||||
|
EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
|
||||||
|
layer being IEEE 802.1X if EAP module is built for other programs than
|
||||||
|
%wpa_supplicant. These terms should be understood to refer to the
|
||||||
|
lower layer as defined in RFC 4137.
|
||||||
|
|
||||||
|
|
||||||
|
\section adding_eap_methods Adding EAP methods
|
||||||
|
|
||||||
|
Each EAP method is implemented as a separate module, usually as one C
|
||||||
|
file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
|
||||||
|
methods use the same interface between the server state machine and
|
||||||
|
method specific functions. This allows new EAP methods to be added
|
||||||
|
without modifying the core EAP state machine implementation.
|
||||||
|
|
||||||
|
New EAP methods need to be registered by adding them into the build
|
||||||
|
(Makefile) and the EAP method registration list in the
|
||||||
|
eap_server_register_methods() function of eap_methods.c. Each EAP
|
||||||
|
method should use a build-time configuration option, e.g., EAP_TLS, in
|
||||||
|
order to make it possible to select which of the methods are included
|
||||||
|
in the build.
|
||||||
|
|
||||||
|
EAP methods must implement the interface defined in eap_i.h. struct
|
||||||
|
eap_method defines the needed function pointers that each EAP method
|
||||||
|
must provide. In addition, the EAP type and name are registered using
|
||||||
|
this structure. This interface is based on section 4.4 of RFC 4137.
|
||||||
|
|
||||||
|
It is recommended that the EAP methods would use generic helper
|
||||||
|
functions, eap_msg_alloc() and eap_hdr_validate() when processing
|
||||||
|
messages. This allows code sharing and can avoid missing some of the
|
||||||
|
needed validation steps for received packets. In addition, these
|
||||||
|
functions make it easier to change between expanded and legacy EAP
|
||||||
|
header, if needed.
|
||||||
|
|
||||||
|
When adding an EAP method that uses a vendor specific EAP type
|
||||||
|
(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
|
||||||
|
must be registered by passing vendor id instead of EAP_VENDOR_IETF to
|
||||||
|
eap_server_method_alloc(). These methods must not try to emulate
|
||||||
|
expanded types by registering a legacy EAP method for type 254. See
|
||||||
|
eap_vendor_test.c for an example of an EAP method implementation that
|
||||||
|
is implemented as an expanded type.
|
||||||
|
|
||||||
|
*/
|
264
hostapd/doc/hostapd.fig
Normal file
264
hostapd/doc/hostapd.fig
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
#FIG 3.2
|
||||||
|
Landscape
|
||||||
|
Center
|
||||||
|
Inches
|
||||||
|
Letter
|
||||||
|
100.00
|
||||||
|
Single
|
||||||
|
-2
|
||||||
|
1200 2
|
||||||
|
6 1875 4050 2925 4350
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
|
||||||
|
-6
|
||||||
|
6 4725 1200 5925 1500
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
|
||||||
|
-6
|
||||||
|
6 6000 2700 7200 3225
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
|
||||||
|
-6
|
||||||
|
6 6000 4950 7200 5475
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
|
||||||
|
-6
|
||||||
|
6 4350 3900 5025 4425
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
|
||||||
|
-6
|
||||||
|
6 4275 2550 5100 2850
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
|
||||||
|
-6
|
||||||
|
6 6000 3900 7200 4425
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
|
||||||
|
-6
|
||||||
|
6 2775 3150 4050 3450
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
|
||||||
|
-6
|
||||||
|
6 3450 1200 4575 1500
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
|
||||||
|
-6
|
||||||
|
6 3525 7800 5775 8100
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
|
||||||
|
-6
|
||||||
|
6 4275 6000 5100 6300
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
|
||||||
|
-6
|
||||||
|
6 8175 4725 9225 5025
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
|
||||||
|
-6
|
||||||
|
6 9300 4725 10350 5025
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
|
||||||
|
-6
|
||||||
|
6 8175 5100 9225 5400
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
|
||||||
|
-6
|
||||||
|
6 9300 5100 10350 5400
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
|
||||||
|
-6
|
||||||
|
6 8175 5475 9225 5775
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
|
||||||
|
-6
|
||||||
|
6 8175 5850 9225 6150
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
|
||||||
|
-6
|
||||||
|
6 8175 6225 9225 6525
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
|
||||||
|
-6
|
||||||
|
6 9300 5850 10350 6150
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
|
||||||
|
-6
|
||||||
|
6 9300 5475 10350 5775
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
|
||||||
|
-6
|
||||||
|
6 8175 6600 9675 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
|
||||||
|
-6
|
||||||
|
6 8700 3450 9375 3750
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
|
||||||
|
-6
|
||||||
|
6 9600 3450 10275 3750
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
|
||||||
|
-6
|
||||||
|
6 6000 5775 7200 6300
|
||||||
|
6 6000 5775 7200 6300
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
|
||||||
|
-6
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
|
||||||
|
-6
|
||||||
|
6 8100 2250 8925 2775
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
|
||||||
|
-6
|
||||||
|
6 3150 5475 4425 5775
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
|
||||||
|
-6
|
||||||
|
6 1950 5550 2625 6075
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
|
||||||
|
-6
|
||||||
|
6 1875 4725 2925 5250
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
|
||||||
|
-6
|
||||||
|
2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
||||||
|
1275 4200 1875 4200
|
||||||
|
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||||
|
4500 2550 3900 1500
|
||||||
|
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||||
|
4800 2550 5400 1500
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
2925 4200 4350 4200
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
5025 3900 6000 3000
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
5025 4200 6000 4200
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4650 6000 4650 4425
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6600 4425 6600 4950
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6600 3225 6600 3900
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
7200 5250 8100 5250
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
9075 4425 9075 3750
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
7200 3000 8700 3525
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4650 3900 4650 2850
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
7200 4125 8700 3675
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6000 4350 5025 6000
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6000 3150 4875 6000
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
|
||||||
|
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
9900 4425 9900 3750
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
|
||||||
|
4350 3900
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4350 3900 4050 3450
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4350 4425 4050 5475
|
||||||
|
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||||
|
2250 7200 4200 7800
|
||||||
|
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
|
||||||
|
7200 7200 5100 7800
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
|
||||||
|
2250 6900 2250 6600 7200 6600 7200 6900
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
3225 6900 3225 6600
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4200 6900 4200 6600
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
5175 6900 5175 6600
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6150 6900 6150 6600
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
4650 6600 4650 6300
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
6600 5475 6600 5775
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
5025 4425 6000 5775
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||||
|
4800 3900 5925 2550 8100 2550
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
7200 3900 8475 2775
|
||||||
|
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
||||||
|
9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
8925 2475 9450 2475
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
2325 5550 2325 5250
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
|
||||||
|
2925 4950 4350 4275
|
||||||
|
2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
|
||||||
|
2850 4725 5775 2400 8100 2400
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
|
||||||
|
4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
|
||||||
|
4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
|
129
hostapd/doc/kerneldoc2doxygen.pl
Executable file
129
hostapd/doc/kerneldoc2doxygen.pl
Executable file
|
@ -0,0 +1,129 @@
|
||||||
|
#!/usr/bin/perl -w
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
# Convert kernel-doc style comments to Doxygen comments.
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# This script reads a C source file from stdin, and writes
|
||||||
|
# to stdout. Normal usage:
|
||||||
|
#
|
||||||
|
# $ mv file.c file.c.gtkdoc
|
||||||
|
# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
|
||||||
|
#
|
||||||
|
# Or to do the same thing with multiple files:
|
||||||
|
# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
|
||||||
|
#
|
||||||
|
# This script may also be suitable for use as a Doxygen input filter,
|
||||||
|
# but that has not been tested.
|
||||||
|
#
|
||||||
|
# Back up your source files before using this script!!
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
|
||||||
|
# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
|
||||||
|
# (modified for kerneldoc format used in wpa_supplicant)
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
# or look at http://www.gnu.org/licenses/gpl.html
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# This function converts a single comment from gtk-doc to Doxygen format.
|
||||||
|
# The parameter does not include the opening or closing lines
|
||||||
|
# (i.e. given a comment like this:
|
||||||
|
# "/**\n"
|
||||||
|
# " * FunctionName:\n"
|
||||||
|
# " * @foo: This describes the foo parameter\n"
|
||||||
|
# " * @bar: This describes the bar parameter\n"
|
||||||
|
# " * @Returns: This describes the return value\n"
|
||||||
|
# " *\n"
|
||||||
|
# " * This describes the function.\n"
|
||||||
|
# " */\n"
|
||||||
|
# This function gets:
|
||||||
|
# " * FunctionName:\n"
|
||||||
|
# " * @foo: This describes the foo parameter\n"
|
||||||
|
# " * @bar: This describes the bar parameter\n"
|
||||||
|
# " * @Returns: This describes the return value\n"
|
||||||
|
# " *\n"
|
||||||
|
# " * This describes the function.\n"
|
||||||
|
# And it returns:
|
||||||
|
# " * This describes the function.\n"
|
||||||
|
# " *\n"
|
||||||
|
# " * @param foo This describes the foo parameter\n"
|
||||||
|
# " * @param bar This describes the bar parameter\n"
|
||||||
|
# " * @return This describes the return value\n"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
sub fixcomment {
|
||||||
|
$t = $_[0];
|
||||||
|
|
||||||
|
# " * func: foo" --> "\brief foo\n"
|
||||||
|
# " * struct bar: foo" --> "\brief foo\n"
|
||||||
|
# If this fails, not a kernel-doc comment ==> return unmodified.
|
||||||
|
($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
|
||||||
|
or return $t;
|
||||||
|
|
||||||
|
# " * Returns: foo" --> "\return foo"
|
||||||
|
$t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
|
||||||
|
|
||||||
|
# " * @foo: bar" --> "\param foo bar"
|
||||||
|
# Handle two common typos: No ":", or "," instead of ":".
|
||||||
|
$t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
|
||||||
|
|
||||||
|
return $t;
|
||||||
|
}
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
# Start of main code
|
||||||
|
|
||||||
|
# Read entire stdin into memory - one multi-line string.
|
||||||
|
$_ = do { local $/; <> };
|
||||||
|
|
||||||
|
s{^/\*\n \*}{/\*\* \\file\n\\brief};
|
||||||
|
s{ \* Copyright}{\\par Copyright\nCopyright};
|
||||||
|
|
||||||
|
# Fix any comments like "/*************" so they don't match.
|
||||||
|
# "/***" ===> "/* *"
|
||||||
|
s{/\*\*\*}{/\* \*}gs;
|
||||||
|
|
||||||
|
# The main comment-detection code.
|
||||||
|
s{
|
||||||
|
( # $1 = Open comment
|
||||||
|
/\*\* # Open comment
|
||||||
|
(?!\*) # Do not match /*** (redundant due to fixup above).
|
||||||
|
[\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
|
||||||
|
)
|
||||||
|
(.*?) # $2 = Body of comment (multi-line)
|
||||||
|
( # $3 = Close comment
|
||||||
|
( # If possible, match the whitespace before the close-comment
|
||||||
|
(?<=\n) # This part only matches after a newline
|
||||||
|
[\t ]* # Eat whitespace
|
||||||
|
)?
|
||||||
|
\*/ # Close comment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
$1 . fixcomment($2) . $3
|
||||||
|
}gesx;
|
||||||
|
# ^^^^ Modes: g - Global, match all occurances.
|
||||||
|
# e - Evaluate the replacement as an expression.
|
||||||
|
# s - Single-line - allows the pattern to match across newlines.
|
||||||
|
# x - eXtended pattern, ignore embedded whitespace
|
||||||
|
# and allow comments.
|
||||||
|
|
||||||
|
# Write results to stdout
|
||||||
|
print $_;
|
||||||
|
|
52
hostapd/doc/mainpage.doxygen
Normal file
52
hostapd/doc/mainpage.doxygen
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
\mainpage Developers' documentation for hostapd
|
||||||
|
|
||||||
|
hostapd includes IEEE 802.11 access point management (authentication /
|
||||||
|
association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
|
||||||
|
RADIUS authentication server functionality. It can be build with
|
||||||
|
various configuration option, e.g., a standalone AP management
|
||||||
|
solution or a RADIUS authentication server with support for number of
|
||||||
|
EAP methods.
|
||||||
|
|
||||||
|
The goal of this documentation and comments in the source code is to
|
||||||
|
give enough information for other developers to understand how hostapd
|
||||||
|
has been implemented, how it can be modified, how new drivers can be
|
||||||
|
supported, and how hostapd can be ported to other operating
|
||||||
|
systems. If any information is missing, feel free to contact Jouni
|
||||||
|
Malinen <j@w1.fi> for more information. Contributions as
|
||||||
|
patch files are also very welcome at the same address. Please note
|
||||||
|
that hostapd is licensed under dual license, GPLv2 or BSD at user's
|
||||||
|
choice. All contributions to hostapd are expected to use compatible
|
||||||
|
licensing terms.
|
||||||
|
|
||||||
|
The source code and read-only access to hostapd CVS repository
|
||||||
|
is available from the project home page at
|
||||||
|
http://hostap.epitest.fi/hostapd/. This developers' documentation
|
||||||
|
is also available as a PDF file from
|
||||||
|
http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
|
||||||
|
|
||||||
|
The design goal for hostapd was to use hardware, driver, and
|
||||||
|
OS independent, portable C code for all WPA functionality. The source
|
||||||
|
code is divided into separate C files as shown on the \ref
|
||||||
|
code_structure "code structure page". All hardware/driver specific
|
||||||
|
functionality is in separate files that implement a \ref
|
||||||
|
driver_wrapper "well-defined driver API". Information about porting
|
||||||
|
to different target boards and operating systems is available on
|
||||||
|
the \ref porting "porting page".
|
||||||
|
|
||||||
|
EAPOL (IEEE 802.1X) state machines are implemented as a separate
|
||||||
|
module that interacts with \ref eap_module "EAP server implementation".
|
||||||
|
Similarly, RADIUS authentication server is in its own separate module.
|
||||||
|
Both IEEE 802.1X and RADIUS authentication server can use EAP server
|
||||||
|
functionality.
|
||||||
|
|
||||||
|
hostapd implements a \ref ctrl_iface_page "control interface" that can
|
||||||
|
be used by external programs to control the operations of the hostapdt
|
||||||
|
daemon and to get status information and event notifications. There is
|
||||||
|
a small C library that provides helper functions to facilitate the use
|
||||||
|
of the control interface. This library can also be used with C++.
|
||||||
|
|
||||||
|
\image html hostapd.png "hostapd modules"
|
||||||
|
\image latex hostapd.eps "hostapd modules" width=15cm
|
||||||
|
|
||||||
|
*/
|
5
hostapd/doc/porting.doxygen
Normal file
5
hostapd/doc/porting.doxygen
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
\page porting Porting to different target boards and operating systems
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
681
hostapd/driver.h
Normal file
681
hostapd/driver.h
Normal file
|
@ -0,0 +1,681 @@
|
||||||
|
/*
|
||||||
|
* hostapd - driver interface definition
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DRIVER_H
|
||||||
|
#define DRIVER_H
|
||||||
|
|
||||||
|
enum hostapd_driver_if_type {
|
||||||
|
HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wpa_driver_ops {
|
||||||
|
const char *name; /* as appears in the config file */
|
||||||
|
|
||||||
|
void * (*init)(struct hostapd_data *hapd);
|
||||||
|
void * (*init_bssid)(struct hostapd_data *hapd, const u8 *bssid);
|
||||||
|
void (*deinit)(void *priv);
|
||||||
|
|
||||||
|
int (*wireless_event_init)(void *priv);
|
||||||
|
void (*wireless_event_deinit)(void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_8021x - enable/disable IEEE 802.1X support
|
||||||
|
* @ifname: Interface name (for multi-SSID/VLAN support)
|
||||||
|
* @priv: driver private data
|
||||||
|
* @enabled: 1 = enable, 0 = disable
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* Configure the kernel driver to enable/disable 802.1X support.
|
||||||
|
* This may be an empty function if 802.1X support is always enabled.
|
||||||
|
*/
|
||||||
|
int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_privacy - enable/disable privacy
|
||||||
|
* @priv: driver private data
|
||||||
|
* @enabled: 1 = privacy enabled, 0 = disabled
|
||||||
|
*
|
||||||
|
* Return: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* Configure privacy.
|
||||||
|
*/
|
||||||
|
int (*set_privacy)(const char *ifname, void *priv, int enabled);
|
||||||
|
|
||||||
|
int (*set_encryption)(const char *ifname, void *priv, const char *alg,
|
||||||
|
const u8 *addr, int idx,
|
||||||
|
const u8 *key, size_t key_len, int txkey);
|
||||||
|
int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
|
||||||
|
int idx, u8 *seq);
|
||||||
|
int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
|
||||||
|
int idx, u8 *seq);
|
||||||
|
int (*flush)(void *priv);
|
||||||
|
int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
|
||||||
|
size_t elem_len);
|
||||||
|
|
||||||
|
int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
|
||||||
|
const u8 *addr);
|
||||||
|
int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
|
||||||
|
size_t data_len, int encrypt, const u8 *own_addr);
|
||||||
|
int (*sta_deauth)(void *priv, const u8 *addr, int reason);
|
||||||
|
int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
|
||||||
|
int (*sta_remove)(void *priv, const u8 *addr);
|
||||||
|
int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
|
||||||
|
int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
|
||||||
|
int len);
|
||||||
|
int (*set_countermeasures)(void *priv, int enabled);
|
||||||
|
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
|
||||||
|
int flags);
|
||||||
|
int (*set_assoc_ap)(void *priv, const u8 *addr);
|
||||||
|
int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
|
||||||
|
u16 capability, u8 *supp_rates, size_t supp_rates_len,
|
||||||
|
int flags);
|
||||||
|
int (*get_inact_sec)(void *priv, const u8 *addr);
|
||||||
|
int (*sta_clear_stats)(void *priv, const u8 *addr);
|
||||||
|
|
||||||
|
int (*set_freq)(void *priv, int mode, int freq);
|
||||||
|
int (*set_rts)(void *priv, int rts);
|
||||||
|
int (*get_rts)(void *priv, int *rts);
|
||||||
|
int (*set_frag)(void *priv, int frag);
|
||||||
|
int (*get_frag)(void *priv, int *frag);
|
||||||
|
int (*set_retry)(void *priv, int short_retry, int long_retry);
|
||||||
|
int (*get_retry)(void *priv, int *short_retry, int *long_retry);
|
||||||
|
|
||||||
|
int (*sta_set_flags)(void *priv, const u8 *addr,
|
||||||
|
int total_flags, int flags_or, int flags_and);
|
||||||
|
int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
|
||||||
|
int mode);
|
||||||
|
int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
|
||||||
|
unsigned char power_level,
|
||||||
|
unsigned char antenna_max);
|
||||||
|
int (*set_regulatory_domain)(void *priv, unsigned int rd);
|
||||||
|
int (*set_country)(void *priv, const char *country);
|
||||||
|
int (*set_ieee80211d)(void *priv, int enabled);
|
||||||
|
int (*set_beacon)(const char *ifname, void *priv,
|
||||||
|
u8 *head, size_t head_len,
|
||||||
|
u8 *tail, size_t tail_len);
|
||||||
|
|
||||||
|
/* Configure internal bridge:
|
||||||
|
* 0 = disabled, i.e., client separation is enabled (no bridging of
|
||||||
|
* packets between associated STAs
|
||||||
|
* 1 = enabled, i.e., bridge packets between associated STAs (default)
|
||||||
|
*/
|
||||||
|
int (*set_internal_bridge)(void *priv, int value);
|
||||||
|
int (*set_beacon_int)(void *priv, int value);
|
||||||
|
int (*set_dtim_period)(const char *ifname, void *priv, int value);
|
||||||
|
/* Configure broadcast SSID mode:
|
||||||
|
* 0 = include SSID in Beacon frames and reply to Probe Request frames
|
||||||
|
* that use broadcast SSID
|
||||||
|
* 1 = hide SSID from Beacon frames and ignore Probe Request frames for
|
||||||
|
* broadcast SSID
|
||||||
|
*/
|
||||||
|
int (*set_broadcast_ssid)(void *priv, int value);
|
||||||
|
int (*set_cts_protect)(void *priv, int value);
|
||||||
|
int (*set_key_tx_rx_threshold)(void *priv, int value);
|
||||||
|
int (*set_preamble)(void *priv, int value);
|
||||||
|
int (*set_short_slot_time)(void *priv, int value);
|
||||||
|
int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
|
||||||
|
int cw_max, int burst_time);
|
||||||
|
int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
|
||||||
|
int (*bss_remove)(void *priv, const char *ifname);
|
||||||
|
int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
|
||||||
|
int (*passive_scan)(void *priv, int now, int our_mode_only,
|
||||||
|
int interval, int _listen, int *channel,
|
||||||
|
int *last_rx);
|
||||||
|
struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
|
||||||
|
u16 *num_modes,
|
||||||
|
u16 *flags);
|
||||||
|
int (*if_add)(const char *iface, void *priv,
|
||||||
|
enum hostapd_driver_if_type type, char *ifname,
|
||||||
|
const u8 *addr);
|
||||||
|
int (*if_update)(void *priv, enum hostapd_driver_if_type type,
|
||||||
|
char *ifname, const u8 *addr);
|
||||||
|
int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
|
||||||
|
const char *ifname, const u8 *addr);
|
||||||
|
int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
|
||||||
|
int vlan_id);
|
||||||
|
/**
|
||||||
|
* commit - Optional commit changes handler
|
||||||
|
* @priv: driver private data
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* This optional handler function can be registered if the driver
|
||||||
|
* interface implementation needs to commit changes (e.g., by setting
|
||||||
|
* network interface up) at the end of initial configuration. If set,
|
||||||
|
* this handler will be called after initial setup has been completed.
|
||||||
|
*/
|
||||||
|
int (*commit)(void *priv);
|
||||||
|
|
||||||
|
int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
|
||||||
|
const u8 *data, size_t data_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
hostapd_driver_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->init == NULL)
|
||||||
|
return NULL;
|
||||||
|
return hapd->driver->init(hapd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
hostapd_driver_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->init_bssid == NULL)
|
||||||
|
return NULL;
|
||||||
|
return hapd->driver->init_bssid(hapd, bssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hostapd_driver_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->deinit == NULL)
|
||||||
|
return;
|
||||||
|
hapd->driver->deinit(hapd->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_wireless_event_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->wireless_event_init == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->wireless_event_init(hapd->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hostapd_wireless_event_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->wireless_event_deinit == NULL)
|
||||||
|
return;
|
||||||
|
hapd->driver->wireless_event_deinit(hapd->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
int enabled)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_ieee8021x(ifname, hapd->drv_priv, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_privacy(hapd->conf->iface, hapd->drv_priv,
|
||||||
|
enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
const char *alg, const u8 *addr, int idx,
|
||||||
|
u8 *key, size_t key_len, int txkey)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_encryption(ifname, hapd->drv_priv, alg, addr,
|
||||||
|
idx, key, key_len, txkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
const u8 *addr, int idx, u8 *seq)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
|
||||||
|
seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
const u8 *addr, int idx, u8 *seq)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->get_seqnum_igtk(ifname, hapd->drv_priv, addr, idx,
|
||||||
|
seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_flush(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->flush == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->flush(hapd->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||||
|
size_t elem_len)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_generic_elem(hapd->conf->iface,
|
||||||
|
hapd->drv_priv, elem, elem_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_read_sta_data(struct hostapd_data *hapd,
|
||||||
|
struct hostap_sta_driver_data *data, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data,
|
||||||
|
size_t data_len, int encrypt)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->send_eapol(hapd->drv_priv, addr, data, data_len,
|
||||||
|
encrypt, hapd->own_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_deauth(hapd->drv_priv, addr, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_disassoc(hapd->drv_priv, addr, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_remove(hapd->drv_priv, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_ssid(hapd->conf->iface, hapd->drv_priv, buf,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_ssid(hapd->conf->iface, hapd->drv_priv, buf,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->send_mgmt_frame == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->send_mgmt_frame(hapd->drv_priv, msg, len, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_assoc_ap(hapd->drv_priv, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_countermeasures(hapd->drv_priv, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
u16 aid, u16 capability, u8 *supp_rates, size_t supp_rates_len,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_add(ifname, hapd->drv_priv, addr, aid,
|
||||||
|
capability, supp_rates, supp_rates_len,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_rts(struct hostapd_data *hapd, int rts)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_rts(hapd->drv_priv, rts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_rts(struct hostapd_data *hapd, int *rts)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_rts(hapd->drv_priv, rts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_frag(struct hostapd_data *hapd, int frag)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_frag(hapd->drv_priv, frag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_frag(struct hostapd_data *hapd, int *frag)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_frag(hapd->drv_priv, frag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_retry(hapd->drv_priv, short_retry,
|
||||||
|
long_retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->get_retry(hapd->drv_priv, short_retry,
|
||||||
|
long_retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||||
|
int total_flags, int flags_or, int flags_and)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
|
||||||
|
flags_or, flags_and);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
|
||||||
|
int *basic_rates, int mode)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
|
||||||
|
basic_rates, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_channel_flag(struct hostapd_data *hapd, int mode, int chan,
|
||||||
|
int flag, unsigned char power_level,
|
||||||
|
unsigned char antenna_max)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_channel_flag == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_channel_flag(hapd->drv_priv, mode, chan, flag,
|
||||||
|
power_level, antenna_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->set_regulatory_domain == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_regulatory_domain(hapd->drv_priv, rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_country(struct hostapd_data *hapd, const char *country)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->set_country == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_country(hapd->drv_priv, country);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->set_ieee80211d == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_ieee80211d(hapd->drv_priv, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
u8 *head, size_t head_len,
|
||||||
|
u8 *tail, size_t tail_len)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_beacon(ifname, hapd->drv_priv, head, head_len,
|
||||||
|
tail, tail_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_internal_bridge(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_beacon_int(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->drv_priv,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_broadcast_ssid(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_cts_protect(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL ||
|
||||||
|
hapd->driver->set_key_tx_rx_threshold == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_key_tx_rx_threshold(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_preamble(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_preamble(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||||
|
int cw_min, int cw_max, int burst_time)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
|
||||||
|
cw_min, cw_max, burst_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->bss_add(hapd->drv_priv, ifname, bssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->bss_remove(hapd->drv_priv, ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
const u8 *mask)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
|
||||||
|
return 1;
|
||||||
|
return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||||
|
char *ifname, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->if_add(hapd->conf->iface, hapd->drv_priv, type,
|
||||||
|
ifname, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||||
|
char *ifname, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->if_update == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->if_update(hapd->drv_priv, type, ifname, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
|
||||||
|
char *ifname, const u8 *addr)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->if_remove(hapd->drv_priv, type, ifname, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
|
||||||
|
int interval, int _listen, int *channel,
|
||||||
|
int *last_rx)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
|
||||||
|
return -1;
|
||||||
|
return hapd->driver->passive_scan(hapd->drv_priv, now, our_mode_only,
|
||||||
|
interval, _listen, channel, last_rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct hostapd_hw_modes *
|
||||||
|
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||||
|
u16 *flags)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
|
||||||
|
return NULL;
|
||||||
|
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
|
||||||
|
const u8 *addr, int vlan_id)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, vlan_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hostapd_driver_commit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (hapd->driver == NULL || hapd->driver->commit == NULL)
|
||||||
|
return 0;
|
||||||
|
return hapd->driver->commit(hapd->drv_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DRIVER_H */
|
838
hostapd/driver_bsd.c
Normal file
838
hostapd/driver_bsd.c
Normal file
|
@ -0,0 +1,838 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Driver interaction with BSD net80211 layer
|
||||||
|
* Copyright (c) 2004, Sam Leffler <sam@errno.com>
|
||||||
|
* Copyright (c) 2004, 2Wire, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#include <net80211/ieee80211.h>
|
||||||
|
#include <net80211/ieee80211_crypto.h>
|
||||||
|
#include <net80211/ieee80211_ioctl.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid conflicts with hostapd definitions by undefining couple of defines
|
||||||
|
* from net80211 header files.
|
||||||
|
*/
|
||||||
|
#undef RSN_VERSION
|
||||||
|
#undef WPA_VERSION
|
||||||
|
#undef WPA_OUI_TYPE
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "l2_packet/l2_packet.h"
|
||||||
|
|
||||||
|
#include "eapol_sm.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "radius/radius.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct bsd_driver_data {
|
||||||
|
struct hostapd_data *hapd; /* back pointer */
|
||||||
|
|
||||||
|
char iface[IFNAMSIZ + 1];
|
||||||
|
struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
|
||||||
|
int ioctl_sock; /* socket for ioctl() use */
|
||||||
|
int wext_sock; /* socket for wireless events */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code);
|
||||||
|
|
||||||
|
static int
|
||||||
|
set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
|
||||||
|
{
|
||||||
|
struct ieee80211req ireq;
|
||||||
|
|
||||||
|
memset(&ireq, 0, sizeof(ireq));
|
||||||
|
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
|
||||||
|
ireq.i_type = op;
|
||||||
|
ireq.i_len = arg_len;
|
||||||
|
ireq.i_data = (void *) arg;
|
||||||
|
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
|
||||||
|
perror("ioctl[SIOCS80211]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
|
||||||
|
{
|
||||||
|
struct ieee80211req ireq;
|
||||||
|
|
||||||
|
memset(&ireq, 0, sizeof(ireq));
|
||||||
|
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
|
||||||
|
ireq.i_type = op;
|
||||||
|
ireq.i_len = arg_len;
|
||||||
|
ireq.i_data = arg;
|
||||||
|
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) {
|
||||||
|
perror("ioctl[SIOCG80211]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ireq.i_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set80211param(struct bsd_driver_data *drv, int op, int arg)
|
||||||
|
{
|
||||||
|
struct ieee80211req ireq;
|
||||||
|
|
||||||
|
memset(&ireq, 0, sizeof(ireq));
|
||||||
|
os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
|
||||||
|
ireq.i_type = op;
|
||||||
|
ireq.i_val = arg;
|
||||||
|
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
|
||||||
|
perror("ioctl[SIOCS80211]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
ether_sprintf(const u8 *addr)
|
||||||
|
{
|
||||||
|
static char buf[sizeof(MACSTR)];
|
||||||
|
|
||||||
|
if (addr != NULL)
|
||||||
|
snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure WPA parameters.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
bsd_configure_wpa(struct bsd_driver_data *drv)
|
||||||
|
{
|
||||||
|
static const char *ciphernames[] =
|
||||||
|
{ "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct hostapd_bss_config *conf = hapd->conf;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
switch (conf->wpa_group) {
|
||||||
|
case WPA_CIPHER_CCMP:
|
||||||
|
v = IEEE80211_CIPHER_AES_CCM;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_TKIP:
|
||||||
|
v = IEEE80211_CIPHER_TKIP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_WEP104:
|
||||||
|
v = IEEE80211_CIPHER_WEP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_WEP40:
|
||||||
|
v = IEEE80211_CIPHER_WEP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_NONE:
|
||||||
|
v = IEEE80211_CIPHER_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown group key cipher %u\n",
|
||||||
|
conf->wpa_group);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
|
||||||
|
__func__, ciphernames[v], v);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) {
|
||||||
|
printf("Unable to set group key cipher to %u (%s)\n",
|
||||||
|
v, ciphernames[v]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (v == IEEE80211_CIPHER_WEP) {
|
||||||
|
/* key length is done only for specific ciphers */
|
||||||
|
v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) {
|
||||||
|
printf("Unable to set group key length to %u\n", v);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v = 0;
|
||||||
|
if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
|
||||||
|
v |= 1<<IEEE80211_CIPHER_AES_CCM;
|
||||||
|
if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
|
||||||
|
v |= 1<<IEEE80211_CIPHER_TKIP;
|
||||||
|
if (conf->wpa_pairwise & WPA_CIPHER_NONE)
|
||||||
|
v |= 1<<IEEE80211_CIPHER_NONE;
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_UCASTCIPHERS, v)) {
|
||||||
|
printf("Unable to set pairwise key ciphers to 0x%x\n", v);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
|
||||||
|
__func__, conf->wpa_key_mgmt);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) {
|
||||||
|
printf("Unable to set key management algorithms to 0x%x\n",
|
||||||
|
conf->wpa_key_mgmt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = 0;
|
||||||
|
if (conf->rsn_preauth)
|
||||||
|
v |= BIT(0);
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
|
||||||
|
__func__, conf->rsn_preauth);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) {
|
||||||
|
printf("Unable to set RSN capabilities to 0x%x\n", v);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa);
|
||||||
|
if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) {
|
||||||
|
printf("Unable to set WPA to %u\n", conf->wpa);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_iface_flags(void *priv, int dev_up)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
|
||||||
|
|
||||||
|
if (drv->ioctl_sock < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
|
||||||
|
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
|
||||||
|
perror("ioctl[SIOCGIFFLAGS]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_up)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
|
||||||
|
perror("ioctl[SIOCSIFFLAGS]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_up) {
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
|
||||||
|
ifr.ifr_mtu = HOSTAPD_MTU;
|
||||||
|
if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
|
||||||
|
perror("ioctl[SIOCSIFMTU]");
|
||||||
|
printf("Setting MTU failed - trying to survive with "
|
||||||
|
"current value\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_ieee8021x(const char *ifname, void *priv, int enabled)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct hostapd_bss_config *conf = hapd->conf;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
||||||
|
|
||||||
|
if (!enabled) {
|
||||||
|
/* XXX restore state */
|
||||||
|
return set80211param(priv, IEEE80211_IOC_AUTHMODE,
|
||||||
|
IEEE80211_AUTH_AUTO);
|
||||||
|
}
|
||||||
|
if (!conf->wpa && !conf->ieee802_1x) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
|
||||||
|
HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (conf->wpa && bsd_configure_wpa(drv) != 0) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
|
||||||
|
HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
|
||||||
|
(conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
|
||||||
|
HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return bsd_set_iface_flags(priv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_privacy(const char *ifname, void *priv, int enabled)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
|
||||||
|
|
||||||
|
return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_mlme mlme;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
|
||||||
|
__func__, ether_sprintf(addr), authorized);
|
||||||
|
|
||||||
|
if (authorized)
|
||||||
|
mlme.im_op = IEEE80211_MLME_AUTHORIZE;
|
||||||
|
else
|
||||||
|
mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
|
||||||
|
mlme.im_reason = 0;
|
||||||
|
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or,
|
||||||
|
int flags_and)
|
||||||
|
{
|
||||||
|
/* For now, only support setting Authorized flag */
|
||||||
|
if (flags_or & WLAN_STA_AUTHORIZED)
|
||||||
|
return bsd_set_sta_authorized(priv, addr, 1);
|
||||||
|
if (!(flags_and & WLAN_STA_AUTHORIZED))
|
||||||
|
return bsd_set_sta_authorized(priv, addr, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_del_key(void *priv, const u8 *addr, int key_idx)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_del_key wk;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
|
||||||
|
__func__, ether_sprintf(addr), key_idx);
|
||||||
|
|
||||||
|
memset(&wk, 0, sizeof(wk));
|
||||||
|
if (addr != NULL) {
|
||||||
|
memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */
|
||||||
|
} else {
|
||||||
|
wk.idk_keyix = key_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_key(const char *ifname, void *priv, const char *alg,
|
||||||
|
const u8 *addr, int key_idx,
|
||||||
|
const u8 *key, size_t key_len, int txkey)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_key wk;
|
||||||
|
u_int8_t cipher;
|
||||||
|
|
||||||
|
if (strcmp(alg, "none") == 0)
|
||||||
|
return bsd_del_key(drv, addr, key_idx);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
|
||||||
|
__func__, alg, ether_sprintf(addr), key_idx);
|
||||||
|
|
||||||
|
if (strcmp(alg, "WEP") == 0)
|
||||||
|
cipher = IEEE80211_CIPHER_WEP;
|
||||||
|
else if (strcmp(alg, "TKIP") == 0)
|
||||||
|
cipher = IEEE80211_CIPHER_TKIP;
|
||||||
|
else if (strcmp(alg, "CCMP") == 0)
|
||||||
|
cipher = IEEE80211_CIPHER_AES_CCM;
|
||||||
|
else {
|
||||||
|
printf("%s: unknown/unsupported algorithm %s\n",
|
||||||
|
__func__, alg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_len > sizeof(wk.ik_keydata)) {
|
||||||
|
printf("%s: key length %d too big\n", __func__, key_len);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&wk, 0, sizeof(wk));
|
||||||
|
wk.ik_type = cipher;
|
||||||
|
wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
|
||||||
|
if (addr == NULL) {
|
||||||
|
memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
|
||||||
|
wk.ik_keyix = key_idx;
|
||||||
|
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
|
||||||
|
} else {
|
||||||
|
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
wk.ik_keyix = IEEE80211_KEYIX_NONE;
|
||||||
|
}
|
||||||
|
wk.ik_keylen = key_len;
|
||||||
|
memcpy(wk.ik_keydata, key, key_len);
|
||||||
|
|
||||||
|
return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
|
||||||
|
u8 *seq)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_key wk;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
|
||||||
|
__func__, ether_sprintf(addr), idx);
|
||||||
|
|
||||||
|
memset(&wk, 0, sizeof(wk));
|
||||||
|
if (addr == NULL)
|
||||||
|
memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
|
||||||
|
else
|
||||||
|
memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
wk.ik_keyix = idx;
|
||||||
|
|
||||||
|
if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
|
||||||
|
printf("Failed to get encryption.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* wk.ik_keytsc is in host byte order (big endian), need to
|
||||||
|
* swap it to match with the byte order used in WPA.
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
u8 tmp[WPA_KEY_RSC_LEN];
|
||||||
|
memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
|
||||||
|
for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
|
||||||
|
seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* WORDS_BIGENDIAN */
|
||||||
|
memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
|
||||||
|
#endif /* WORDS_BIGENDIAN */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_flush(void *priv)
|
||||||
|
{
|
||||||
|
u8 allsta[IEEE80211_ADDR_LEN];
|
||||||
|
|
||||||
|
memset(allsta, 0xff, IEEE80211_ADDR_LEN);
|
||||||
|
return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
|
||||||
|
const u8 *addr)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_sta_stats stats;
|
||||||
|
|
||||||
|
memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) {
|
||||||
|
/* XXX? do packets counts include non-data frames? */
|
||||||
|
data->rx_packets = stats.is_stats.ns_rx_data;
|
||||||
|
data->rx_bytes = stats.is_stats.ns_rx_bytes;
|
||||||
|
data->tx_packets = stats.is_stats.ns_tx_data;
|
||||||
|
data->tx_bytes = stats.is_stats.ns_tx_bytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Do nothing; we setup parameters at startup that define the
|
||||||
|
* contents of the beacon information element.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_sta_deauth(void *priv, const u8 *addr, int reason_code)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_mlme mlme;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
|
||||||
|
__func__, ether_sprintf(addr), reason_code);
|
||||||
|
|
||||||
|
mlme.im_op = IEEE80211_MLME_DEAUTH;
|
||||||
|
mlme.im_reason = reason_code;
|
||||||
|
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
struct ieee80211req_mlme mlme;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
|
||||||
|
__func__, ether_sprintf(addr), reason_code);
|
||||||
|
|
||||||
|
mlme.im_op = IEEE80211_MLME_DISASSOC;
|
||||||
|
mlme.im_reason = reason_code;
|
||||||
|
memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct hostapd_bss_config *conf = hapd->conf;
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "deassociated");
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, addr);
|
||||||
|
if (sta != NULL) {
|
||||||
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||||
|
if (conf->wpa)
|
||||||
|
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
|
||||||
|
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
|
||||||
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct hostapd_bss_config *conf = hapd->conf;
|
||||||
|
struct sta_info *sta;
|
||||||
|
struct ieee80211req_wpaie ie;
|
||||||
|
int new_assoc, ielen, res;
|
||||||
|
|
||||||
|
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "associated");
|
||||||
|
|
||||||
|
sta = ap_sta_add(hapd, addr);
|
||||||
|
if (sta == NULL)
|
||||||
|
return -1;
|
||||||
|
/*
|
||||||
|
* Fetch and validate any negotiated WPA/RSN parameters.
|
||||||
|
*/
|
||||||
|
if (conf->wpa) {
|
||||||
|
memset(&ie, 0, sizeof(ie));
|
||||||
|
memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
|
||||||
|
if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
|
||||||
|
printf("Failed to get WPA/RSN information element.\n");
|
||||||
|
return -1; /* XXX not right */
|
||||||
|
}
|
||||||
|
ielen = ie.wpa_ie[1];
|
||||||
|
if (ielen == 0) {
|
||||||
|
printf("No WPA/RSN information element for station!\n");
|
||||||
|
return -1; /* XXX not right */
|
||||||
|
}
|
||||||
|
ielen += 2;
|
||||||
|
if (sta->wpa_sm == NULL)
|
||||||
|
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
|
||||||
|
sta->addr);
|
||||||
|
if (sta->wpa_sm == NULL) {
|
||||||
|
printf("Failed to initialize WPA state machine\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||||
|
ie.wpa_ie, ielen, NULL, 0);
|
||||||
|
if (res != WPA_IE_OK) {
|
||||||
|
printf("WPA/RSN information element rejected? "
|
||||||
|
"(res %u)\n", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that the internal station state is setup
|
||||||
|
* kick the authenticator into action.
|
||||||
|
*/
|
||||||
|
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||||
|
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||||
|
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||||
|
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||||
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <net/route.h>
|
||||||
|
#include <net80211/ieee80211_freebsd.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = ctx;
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
char buf[2048];
|
||||||
|
struct if_announcemsghdr *ifan;
|
||||||
|
struct rt_msghdr *rtm;
|
||||||
|
struct ieee80211_michael_event *mic;
|
||||||
|
struct ieee80211_join_event *join;
|
||||||
|
struct ieee80211_leave_event *leave;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = read(sock, buf, sizeof(buf));
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
|
perror("read(PF_ROUTE)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtm = (struct rt_msghdr *) buf;
|
||||||
|
if (rtm->rtm_version != RTM_VERSION) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Routing message version %d not "
|
||||||
|
"understood\n", rtm->rtm_version);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ifan = (struct if_announcemsghdr *) rtm;
|
||||||
|
switch (rtm->rtm_type) {
|
||||||
|
case RTM_IEEE80211:
|
||||||
|
switch (ifan->ifan_what) {
|
||||||
|
case RTM_IEEE80211_ASSOC:
|
||||||
|
case RTM_IEEE80211_REASSOC:
|
||||||
|
case RTM_IEEE80211_DISASSOC:
|
||||||
|
case RTM_IEEE80211_SCAN:
|
||||||
|
break;
|
||||||
|
case RTM_IEEE80211_LEAVE:
|
||||||
|
leave = (struct ieee80211_leave_event *) &ifan[1];
|
||||||
|
bsd_del_sta(drv, leave->iev_addr);
|
||||||
|
break;
|
||||||
|
case RTM_IEEE80211_JOIN:
|
||||||
|
#ifdef RTM_IEEE80211_REJOIN
|
||||||
|
case RTM_IEEE80211_REJOIN:
|
||||||
|
#endif
|
||||||
|
join = (struct ieee80211_join_event *) &ifan[1];
|
||||||
|
bsd_new_sta(drv, join->iev_addr);
|
||||||
|
break;
|
||||||
|
case RTM_IEEE80211_REPLAY:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
case RTM_IEEE80211_MICHAEL:
|
||||||
|
mic = (struct ieee80211_michael_event *) &ifan[1];
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Michael MIC failure wireless event: "
|
||||||
|
"keyix=%u src_addr=" MACSTR, mic->iev_keyix,
|
||||||
|
MAC2STR(mic->iev_src));
|
||||||
|
ieee80211_michael_mic_failure(hapd, mic->iev_src, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_wireless_event_init(void *priv)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
drv->wext_sock = -1;
|
||||||
|
|
||||||
|
s = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||||
|
if (s < 0) {
|
||||||
|
perror("socket(PF_ROUTE,SOCK_RAW)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL);
|
||||||
|
drv->wext_sock = s;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsd_wireless_event_deinit(void *priv)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
|
||||||
|
if (drv != NULL) {
|
||||||
|
if (drv->wext_sock < 0)
|
||||||
|
return;
|
||||||
|
eloop_unregister_read_sock(drv->wext_sock);
|
||||||
|
close(drv->wext_sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
|
||||||
|
int encrypt, const u8 *own_addr)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
unsigned char buf[3000];
|
||||||
|
unsigned char *bp = buf;
|
||||||
|
struct l2_ethhdr *eth;
|
||||||
|
size_t len;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepend the Etherent header. If the caller left us
|
||||||
|
* space at the front we could just insert it but since
|
||||||
|
* we don't know we copy to a local buffer. Given the frequency
|
||||||
|
* and size of frames this probably doesn't matter.
|
||||||
|
*/
|
||||||
|
len = data_len + sizeof(struct l2_ethhdr);
|
||||||
|
if (len > sizeof(buf)) {
|
||||||
|
bp = malloc(len);
|
||||||
|
if (bp == NULL) {
|
||||||
|
printf("EAPOL frame discarded, cannot malloc temp "
|
||||||
|
"buffer of size %u!\n", len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eth = (struct l2_ethhdr *) bp;
|
||||||
|
memcpy(eth->h_dest, addr, ETH_ALEN);
|
||||||
|
memcpy(eth->h_source, own_addr, ETH_ALEN);
|
||||||
|
eth->h_proto = htons(ETH_P_EAPOL);
|
||||||
|
memcpy(eth+1, data, data_len);
|
||||||
|
|
||||||
|
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
|
||||||
|
|
||||||
|
status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
|
||||||
|
|
||||||
|
if (bp != buf)
|
||||||
|
free(bp);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = ctx;
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, src_addr);
|
||||||
|
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
|
||||||
|
printf("Data frame from not associated STA %s\n",
|
||||||
|
ether_sprintf(src_addr));
|
||||||
|
/* XXX cannot happen */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
|
||||||
|
len - sizeof(struct l2_ethhdr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf);
|
||||||
|
|
||||||
|
return ssid_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf);
|
||||||
|
|
||||||
|
return set80211var(drv, IEEE80211_IOC_SSID, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
bsd_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv;
|
||||||
|
|
||||||
|
drv = os_zalloc(sizeof(struct bsd_driver_data));
|
||||||
|
if (drv == NULL) {
|
||||||
|
printf("Could not allocate memory for bsd driver data\n");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv->hapd = hapd;
|
||||||
|
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (drv->ioctl_sock < 0) {
|
||||||
|
perror("socket[PF_INET,SOCK_DGRAM]");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
|
||||||
|
|
||||||
|
drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
|
||||||
|
handle_read, drv, 1);
|
||||||
|
if (drv->sock_xmit == NULL)
|
||||||
|
goto bad;
|
||||||
|
if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
|
||||||
|
goto bad;
|
||||||
|
|
||||||
|
bsd_set_iface_flags(drv, 0); /* mark down during setup */
|
||||||
|
|
||||||
|
return drv;
|
||||||
|
bad:
|
||||||
|
if (drv->sock_xmit != NULL)
|
||||||
|
l2_packet_deinit(drv->sock_xmit);
|
||||||
|
if (drv->ioctl_sock >= 0)
|
||||||
|
close(drv->ioctl_sock);
|
||||||
|
if (drv != NULL)
|
||||||
|
free(drv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
bsd_deinit(void *priv)
|
||||||
|
{
|
||||||
|
struct bsd_driver_data *drv = priv;
|
||||||
|
|
||||||
|
(void) bsd_set_iface_flags(drv, 0);
|
||||||
|
if (drv->ioctl_sock >= 0)
|
||||||
|
close(drv->ioctl_sock);
|
||||||
|
if (drv->sock_xmit != NULL)
|
||||||
|
l2_packet_deinit(drv->sock_xmit);
|
||||||
|
free(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct wpa_driver_ops wpa_driver_bsd_ops = {
|
||||||
|
.name = "bsd",
|
||||||
|
.init = bsd_init,
|
||||||
|
.deinit = bsd_deinit,
|
||||||
|
.set_ieee8021x = bsd_set_ieee8021x,
|
||||||
|
.set_privacy = bsd_set_privacy,
|
||||||
|
.set_encryption = bsd_set_key,
|
||||||
|
.get_seqnum = bsd_get_seqnum,
|
||||||
|
.flush = bsd_flush,
|
||||||
|
.set_generic_elem = bsd_set_opt_ie,
|
||||||
|
.wireless_event_init = bsd_wireless_event_init,
|
||||||
|
.wireless_event_deinit = bsd_wireless_event_deinit,
|
||||||
|
.sta_set_flags = bsd_sta_set_flags,
|
||||||
|
.read_sta_data = bsd_read_sta_driver_data,
|
||||||
|
.send_eapol = bsd_send_eapol,
|
||||||
|
.sta_disassoc = bsd_sta_disassoc,
|
||||||
|
.sta_deauth = bsd_sta_deauth,
|
||||||
|
.set_ssid = bsd_set_ssid,
|
||||||
|
.get_ssid = bsd_get_ssid,
|
||||||
|
};
|
1235
hostapd/driver_hostap.c
Normal file
1235
hostapd/driver_hostap.c
Normal file
File diff suppressed because it is too large
Load diff
1363
hostapd/driver_madwifi.c
Normal file
1363
hostapd/driver_madwifi.c
Normal file
File diff suppressed because it is too large
Load diff
2382
hostapd/driver_nl80211.c
Normal file
2382
hostapd/driver_nl80211.c
Normal file
File diff suppressed because it is too large
Load diff
1086
hostapd/driver_prism54.c
Normal file
1086
hostapd/driver_prism54.c
Normal file
File diff suppressed because it is too large
Load diff
1167
hostapd/driver_test.c
Normal file
1167
hostapd/driver_test.c
Normal file
File diff suppressed because it is too large
Load diff
373
hostapd/driver_wired.c
Normal file
373
hostapd/driver_wired.c
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Kernel driver communication for wired (Ethernet) drivers
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#ifdef USE_KERNEL_HEADERS
|
||||||
|
#include <asm/types.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#include <linux/if_ether.h> /* The L2 protocols */
|
||||||
|
#include <linux/if_arp.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#else /* USE_KERNEL_HEADERS */
|
||||||
|
#include <net/if_arp.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netpacket/packet.h>
|
||||||
|
#endif /* USE_KERNEL_HEADERS */
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "accounting.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct wired_driver_data {
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
|
||||||
|
int sock; /* raw packet socket for driver access */
|
||||||
|
int dhcp_sock; /* socket for dhcp packets */
|
||||||
|
int use_pae_group_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: detecting new devices should eventually be changed from using DHCP
|
||||||
|
* snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
|
||||||
|
* based on ebtables, etc. */
|
||||||
|
|
||||||
|
struct dhcp_message {
|
||||||
|
u_int8_t op;
|
||||||
|
u_int8_t htype;
|
||||||
|
u_int8_t hlen;
|
||||||
|
u_int8_t hops;
|
||||||
|
u_int32_t xid;
|
||||||
|
u_int16_t secs;
|
||||||
|
u_int16_t flags;
|
||||||
|
u_int32_t ciaddr;
|
||||||
|
u_int32_t yiaddr;
|
||||||
|
u_int32_t siaddr;
|
||||||
|
u_int32_t giaddr;
|
||||||
|
u_int8_t chaddr[16];
|
||||||
|
u_int8_t sname[64];
|
||||||
|
u_int8_t file[128];
|
||||||
|
u_int32_t cookie;
|
||||||
|
u_int8_t options[308]; /* 312 - cookie */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, addr);
|
||||||
|
if (sta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
|
||||||
|
" - adding a new STA", MAC2STR(addr));
|
||||||
|
sta = ap_sta_add(hapd, addr);
|
||||||
|
if (sta) {
|
||||||
|
hostapd_new_assoc_sta(hapd, sta, 0);
|
||||||
|
accounting_sta_get_id(hapd, sta);
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
|
||||||
|
MAC2STR(addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_data(struct hostapd_data *hapd, unsigned char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct ieee8023_hdr *hdr;
|
||||||
|
u8 *pos, *sa;
|
||||||
|
size_t left;
|
||||||
|
|
||||||
|
/* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
|
||||||
|
* 2 byte ethertype */
|
||||||
|
if (len < 14) {
|
||||||
|
wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
|
||||||
|
(unsigned long) len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (struct ieee8023_hdr *) buf;
|
||||||
|
|
||||||
|
switch (ntohs(hdr->ethertype)) {
|
||||||
|
case ETH_P_PAE:
|
||||||
|
wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
|
||||||
|
sa = hdr->src;
|
||||||
|
wired_possible_new_sta(hapd, sa);
|
||||||
|
|
||||||
|
pos = (u8 *) (hdr + 1);
|
||||||
|
left = len - sizeof(*hdr);
|
||||||
|
|
||||||
|
ieee802_1x_receive(hapd, sa, pos, left);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
|
||||||
|
ntohs(hdr->ethertype));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
|
||||||
|
int len;
|
||||||
|
unsigned char buf[3000];
|
||||||
|
|
||||||
|
len = recv(sock, buf, sizeof(buf), 0);
|
||||||
|
if (len < 0) {
|
||||||
|
perror("recv");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_data(hapd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
|
||||||
|
int len;
|
||||||
|
unsigned char buf[3000];
|
||||||
|
struct dhcp_message *msg;
|
||||||
|
u8 *mac_address;
|
||||||
|
|
||||||
|
len = recv(sock, buf, sizeof(buf), 0);
|
||||||
|
if (len < 0) {
|
||||||
|
perror("recv");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* must contain at least dhcp_message->chaddr */
|
||||||
|
if (len < 44) {
|
||||||
|
wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = (struct dhcp_message *) buf;
|
||||||
|
mac_address = (u8 *) &(msg->chaddr);
|
||||||
|
|
||||||
|
wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
|
||||||
|
MAC2STR(mac_address));
|
||||||
|
|
||||||
|
wired_possible_new_sta(hapd, mac_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wired_init_sockets(struct wired_driver_data *drv)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = drv->hapd;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct sockaddr_ll addr;
|
||||||
|
struct sockaddr_in addr2;
|
||||||
|
struct packet_mreq mreq;
|
||||||
|
u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP;
|
||||||
|
int n = 1;
|
||||||
|
|
||||||
|
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
|
||||||
|
if (drv->sock < 0) {
|
||||||
|
perror("socket[PF_PACKET,SOCK_RAW]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) {
|
||||||
|
printf("Could not register read socket\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
|
||||||
|
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||||
|
perror("ioctl(SIOCGIFINDEX)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sll_family = AF_PACKET;
|
||||||
|
addr.sll_ifindex = ifr.ifr_ifindex;
|
||||||
|
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
|
||||||
|
addr.sll_ifindex);
|
||||||
|
|
||||||
|
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filter multicast address */
|
||||||
|
memset(&mreq, 0, sizeof(mreq));
|
||||||
|
mreq.mr_ifindex = ifr.ifr_ifindex;
|
||||||
|
mreq.mr_type = PACKET_MR_MULTICAST;
|
||||||
|
mreq.mr_alen = 6;
|
||||||
|
memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen);
|
||||||
|
|
||||||
|
if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
|
||||||
|
sizeof(mreq)) < 0) {
|
||||||
|
perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
|
||||||
|
if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
|
||||||
|
perror("ioctl(SIOCGIFHWADDR)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
|
||||||
|
printf("Invalid HW-addr family 0x%04x\n",
|
||||||
|
ifr.ifr_hwaddr.sa_family);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||||
|
|
||||||
|
/* setup dhcp listen socket for sta detection */
|
||||||
|
if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
||||||
|
perror("socket call failed for dhcp");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL))
|
||||||
|
{
|
||||||
|
printf("Could not register read socket\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&addr2, 0, sizeof(addr2));
|
||||||
|
addr2.sin_family = AF_INET;
|
||||||
|
addr2.sin_port = htons(67);
|
||||||
|
addr2.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
|
||||||
|
sizeof(n)) == -1) {
|
||||||
|
perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
|
||||||
|
sizeof(n)) == -1) {
|
||||||
|
perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ);
|
||||||
|
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
|
||||||
|
(char *) &ifr, sizeof(ifr)) < 0) {
|
||||||
|
perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
|
||||||
|
sizeof(struct sockaddr)) == -1) {
|
||||||
|
perror("bind");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wired_send_eapol(void *priv, const u8 *addr,
|
||||||
|
const u8 *data, size_t data_len, int encrypt,
|
||||||
|
const u8 *own_addr)
|
||||||
|
{
|
||||||
|
struct wired_driver_data *drv = priv;
|
||||||
|
u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP;
|
||||||
|
struct ieee8023_hdr *hdr;
|
||||||
|
size_t len;
|
||||||
|
u8 *pos;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
len = sizeof(*hdr) + data_len;
|
||||||
|
hdr = os_zalloc(len);
|
||||||
|
if (hdr == NULL) {
|
||||||
|
printf("malloc() failed for wired_send_eapol(len=%lu)\n",
|
||||||
|
(unsigned long) len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
|
||||||
|
ETH_ALEN);
|
||||||
|
memcpy(hdr->src, own_addr, ETH_ALEN);
|
||||||
|
hdr->ethertype = htons(ETH_P_PAE);
|
||||||
|
|
||||||
|
pos = (u8 *) (hdr + 1);
|
||||||
|
memcpy(pos, data, data_len);
|
||||||
|
|
||||||
|
res = send(drv->sock, (u8 *) hdr, len, 0);
|
||||||
|
free(hdr);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
perror("wired_send_eapol: send");
|
||||||
|
printf("wired_send_eapol - packet len: %lu - failed\n",
|
||||||
|
(unsigned long) len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void * wired_driver_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct wired_driver_data *drv;
|
||||||
|
|
||||||
|
drv = os_zalloc(sizeof(struct wired_driver_data));
|
||||||
|
if (drv == NULL) {
|
||||||
|
printf("Could not allocate memory for wired driver data\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv->hapd = hapd;
|
||||||
|
drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
|
||||||
|
|
||||||
|
if (wired_init_sockets(drv)) {
|
||||||
|
free(drv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wired_driver_deinit(void *priv)
|
||||||
|
{
|
||||||
|
struct wired_driver_data *drv = priv;
|
||||||
|
|
||||||
|
if (drv->sock >= 0)
|
||||||
|
close(drv->sock);
|
||||||
|
|
||||||
|
if (drv->dhcp_sock >= 0)
|
||||||
|
close(drv->dhcp_sock);
|
||||||
|
|
||||||
|
free(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const struct wpa_driver_ops wpa_driver_wired_ops = {
|
||||||
|
.name = "wired",
|
||||||
|
.init = wired_driver_init,
|
||||||
|
.deinit = wired_driver_deinit,
|
||||||
|
.send_eapol = wired_send_eapol,
|
||||||
|
};
|
65
hostapd/drivers.c
Normal file
65
hostapd/drivers.c
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* hostapd / driver interface list
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_DRIVER_HOSTAP
|
||||||
|
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
|
||||||
|
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||||
|
#ifdef CONFIG_DRIVER_NL80211
|
||||||
|
extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
|
||||||
|
#endif /* CONFIG_DRIVER_NL80211 */
|
||||||
|
#ifdef CONFIG_DRIVER_PRISM54
|
||||||
|
extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
|
||||||
|
#endif /* CONFIG_DRIVER_PRISM54 */
|
||||||
|
#ifdef CONFIG_DRIVER_MADWIFI
|
||||||
|
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
|
||||||
|
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||||
|
#ifdef CONFIG_DRIVER_BSD
|
||||||
|
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
|
||||||
|
#endif /* CONFIG_DRIVER_BSD */
|
||||||
|
#ifdef CONFIG_DRIVER_WIRED
|
||||||
|
extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
|
||||||
|
#endif /* CONFIG_DRIVER_WIRED */
|
||||||
|
#ifdef CONFIG_DRIVER_TEST
|
||||||
|
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
|
||||||
|
#endif /* CONFIG_DRIVER_TEST */
|
||||||
|
|
||||||
|
|
||||||
|
struct wpa_driver_ops *hostapd_drivers[] =
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_DRIVER_HOSTAP
|
||||||
|
&wpa_driver_hostap_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_HOSTAP */
|
||||||
|
#ifdef CONFIG_DRIVER_NL80211
|
||||||
|
&wpa_driver_nl80211_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_NL80211 */
|
||||||
|
#ifdef CONFIG_DRIVER_PRISM54
|
||||||
|
&wpa_driver_prism54_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_PRISM54 */
|
||||||
|
#ifdef CONFIG_DRIVER_MADWIFI
|
||||||
|
&wpa_driver_madwifi_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_MADWIFI */
|
||||||
|
#ifdef CONFIG_DRIVER_BSD
|
||||||
|
&wpa_driver_bsd_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_BSD */
|
||||||
|
#ifdef CONFIG_DRIVER_WIRED
|
||||||
|
&wpa_driver_wired_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_WIRED */
|
||||||
|
#ifdef CONFIG_DRIVER_TEST
|
||||||
|
&wpa_driver_test_ops,
|
||||||
|
#endif /* CONFIG_DRIVER_TEST */
|
||||||
|
NULL
|
||||||
|
};
|
74
hostapd/eap_testing.txt
Normal file
74
hostapd/eap_testing.txt
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
|
||||||
|
|
||||||
|
Test matrix
|
||||||
|
|
||||||
|
+) tested successfully
|
||||||
|
F) failed
|
||||||
|
-) peer did not support
|
||||||
|
?) not tested
|
||||||
|
|
||||||
|
XSupplicant --------------------------------.
|
||||||
|
Intel PROSet ---------------------------. |
|
||||||
|
Windows XP -------------------------. | |
|
||||||
|
Mac OS X 10.4 ------------------. | | |
|
||||||
|
Nokia S60 ------------------. | | | |
|
||||||
|
wpa_supplicant ---------. | | | | |
|
||||||
|
| | | | | |
|
||||||
|
|
||||||
|
EAP-MD5 + - ? ? -
|
||||||
|
EAP-GTC + - ? - -
|
||||||
|
EAP-MSCHAPv2 + - ? - -
|
||||||
|
EAP-TLS + + +1 + +
|
||||||
|
EAP-PEAPv0/MSCHAPv2 + + + + + +
|
||||||
|
EAP-PEAPv0/GTC + + + - +
|
||||||
|
EAP-PEAPv0/MD5 + - + - -
|
||||||
|
EAP-PEAPv0/TLS + F - + +
|
||||||
|
EAP-PEAPv0/SIM + + - - -
|
||||||
|
EAP-PEAPv0/AKA + + - - -
|
||||||
|
EAP-PEAPv0/PSK + - - - -
|
||||||
|
EAP-PEAPv0/PAX + - - - -
|
||||||
|
EAP-PEAPv0/SAKE + - - - -
|
||||||
|
EAP-PEAPv0/GPSK + - - - -
|
||||||
|
EAP-PEAPv1/MSCHAPv2 + + + - + +
|
||||||
|
EAP-PEAPv1/GTC + + + - +
|
||||||
|
EAP-PEAPv1/MD5 + - + - -
|
||||||
|
EAP-PEAPv1/TLS + F - - +
|
||||||
|
EAP-PEAPv1/SIM + + - - -
|
||||||
|
EAP-PEAPv1/AKA + + - - -
|
||||||
|
EAP-PEAPv1/PSK + - - - -
|
||||||
|
EAP-PEAPv1/PAX + - - - -
|
||||||
|
EAP-PEAPv1/SAKE + - - - -
|
||||||
|
EAP-PEAPv1/GPSK + - - - -
|
||||||
|
EAP-TTLS/CHAP + - + - + +
|
||||||
|
EAP-TTLS/MSCHAP + - + - + +
|
||||||
|
EAP-TTLS/MSCHAPv2 + + + - + +
|
||||||
|
EAP-TTLS/PAP + - + - + +
|
||||||
|
EAP-TTLS/EAP-MD5 + - - - - +
|
||||||
|
EAP-TTLS/EAP-GTC + + - - -
|
||||||
|
EAP-TTLS/EAP-MSCHAPv2 + + - - -
|
||||||
|
EAP-TTLS/EAP-TLS + F - - -
|
||||||
|
EAP-TTLS/EAP-SIM + + - - -
|
||||||
|
EAP-TTLS/EAP-AKA + + - - -
|
||||||
|
EAP-SIM + + - - +
|
||||||
|
EAP-AKA + + - - -
|
||||||
|
EAP-PAX + - - - -
|
||||||
|
EAP-SAKE + - - - -
|
||||||
|
EAP-GPSK + - - - -
|
||||||
|
EAP-FAST/MSCHAPv2(prov) + - F - F
|
||||||
|
EAP-FAST/GTC(auth) + - + - +
|
||||||
|
EAP-FAST/MSCHAPv2(aprov)+ - F - F
|
||||||
|
EAP-FAST/GTC(aprov) + - F - F
|
||||||
|
EAP-FAST/MD5(aprov) + - - - -
|
||||||
|
EAP-FAST/TLS(aprov) + - - - -
|
||||||
|
EAP-FAST/SIM(aprov) + - - - -
|
||||||
|
EAP-FAST/AKA(aprov) + - - - -
|
||||||
|
EAP-FAST/MSCHAPv2(auth) + - + - +
|
||||||
|
EAP-FAST/MD5(auth) + - + - -
|
||||||
|
EAP-FAST/TLS(auth) + - - - -
|
||||||
|
EAP-FAST/SIM(auth) + - - - -
|
||||||
|
EAP-FAST/AKA(auth) + - - - -
|
||||||
|
EAP-IKEv2 + - - - -
|
||||||
|
|
||||||
|
1) EAP-TLS itself worked, but peer certificate validation failed at
|
||||||
|
least when using the internal TLS server (peer included incorrect
|
||||||
|
certificates in the chain?)
|
1290
hostapd/eapol_sm.c
Normal file
1290
hostapd/eapol_sm.c
Normal file
File diff suppressed because it is too large
Load diff
253
hostapd/eapol_sm.h
Normal file
253
hostapd/eapol_sm.h
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.1X-2004 Authenticator - EAPOL state machine
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EAPOL_SM_H
|
||||||
|
#define EAPOL_SM_H
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
/* IEEE Std 802.1X-2004, Ch. 8.2 */
|
||||||
|
|
||||||
|
typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
|
||||||
|
PortTypes;
|
||||||
|
typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
|
||||||
|
typedef enum { Both = 0, In = 1 } ControlledDirection;
|
||||||
|
typedef unsigned int Counter;
|
||||||
|
|
||||||
|
struct eap_sm;
|
||||||
|
|
||||||
|
struct radius_attr_data {
|
||||||
|
u8 *data;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct radius_class_data {
|
||||||
|
struct radius_attr_data *attr;
|
||||||
|
size_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct eapol_auth_config {
|
||||||
|
int eap_reauth_period;
|
||||||
|
int wpa;
|
||||||
|
int individual_wep_key_len;
|
||||||
|
int eap_server;
|
||||||
|
void *ssl_ctx;
|
||||||
|
void *eap_sim_db_priv;
|
||||||
|
char *eap_req_id_text; /* a copy of this will be allocated */
|
||||||
|
size_t eap_req_id_text_len;
|
||||||
|
u8 *pac_opaque_encr_key;
|
||||||
|
char *eap_fast_a_id;
|
||||||
|
int eap_sim_aka_result_ind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointer to hostapd data. This is a temporary workaround for
|
||||||
|
* transition phase and will be removed once IEEE 802.1X/EAPOL code is
|
||||||
|
* separated more cleanly from rest of hostapd.
|
||||||
|
*/
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eap_user;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
|
||||||
|
} eapol_logger_level;
|
||||||
|
|
||||||
|
struct eapol_auth_cb {
|
||||||
|
void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data,
|
||||||
|
size_t datalen);
|
||||||
|
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
|
||||||
|
size_t datalen);
|
||||||
|
void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
|
||||||
|
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
|
||||||
|
int phase2, struct eap_user *user);
|
||||||
|
int (*sta_entry_alive)(void *ctx, const u8 *addr);
|
||||||
|
void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level,
|
||||||
|
const char *txt);
|
||||||
|
void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized);
|
||||||
|
void (*abort_auth)(void *ctx, void *sta_ctx);
|
||||||
|
void (*tx_key)(void *ctx, void *sta_ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eapol_authenticator - Global EAPOL authenticator data
|
||||||
|
*/
|
||||||
|
struct eapol_authenticator {
|
||||||
|
struct eapol_auth_config conf;
|
||||||
|
struct eapol_auth_cb cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eapol_state_machine - Per-Supplicant Authenticator state machines
|
||||||
|
*/
|
||||||
|
struct eapol_state_machine {
|
||||||
|
/* timers */
|
||||||
|
int aWhile;
|
||||||
|
int quietWhile;
|
||||||
|
int reAuthWhen;
|
||||||
|
|
||||||
|
/* global variables */
|
||||||
|
Boolean authAbort;
|
||||||
|
Boolean authFail;
|
||||||
|
PortState authPortStatus;
|
||||||
|
Boolean authStart;
|
||||||
|
Boolean authTimeout;
|
||||||
|
Boolean authSuccess;
|
||||||
|
Boolean eapolEap;
|
||||||
|
Boolean initialize;
|
||||||
|
Boolean keyDone;
|
||||||
|
Boolean keyRun;
|
||||||
|
Boolean keyTxEnabled;
|
||||||
|
PortTypes portControl;
|
||||||
|
Boolean portValid;
|
||||||
|
Boolean reAuthenticate;
|
||||||
|
|
||||||
|
/* Port Timers state machine */
|
||||||
|
/* 'Boolean tick' implicitly handled as registered timeout */
|
||||||
|
|
||||||
|
/* Authenticator PAE state machine */
|
||||||
|
enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
|
||||||
|
AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
|
||||||
|
AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
|
||||||
|
AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
|
||||||
|
/* variables */
|
||||||
|
Boolean eapolLogoff;
|
||||||
|
Boolean eapolStart;
|
||||||
|
PortTypes portMode;
|
||||||
|
unsigned int reAuthCount;
|
||||||
|
/* constants */
|
||||||
|
unsigned int quietPeriod; /* default 60; 0..65535 */
|
||||||
|
#define AUTH_PAE_DEFAULT_quietPeriod 60
|
||||||
|
unsigned int reAuthMax; /* default 2 */
|
||||||
|
#define AUTH_PAE_DEFAULT_reAuthMax 2
|
||||||
|
/* counters */
|
||||||
|
Counter authEntersConnecting;
|
||||||
|
Counter authEapLogoffsWhileConnecting;
|
||||||
|
Counter authEntersAuthenticating;
|
||||||
|
Counter authAuthSuccessesWhileAuthenticating;
|
||||||
|
Counter authAuthTimeoutsWhileAuthenticating;
|
||||||
|
Counter authAuthFailWhileAuthenticating;
|
||||||
|
Counter authAuthEapStartsWhileAuthenticating;
|
||||||
|
Counter authAuthEapLogoffWhileAuthenticating;
|
||||||
|
Counter authAuthReauthsWhileAuthenticated;
|
||||||
|
Counter authAuthEapStartsWhileAuthenticated;
|
||||||
|
Counter authAuthEapLogoffWhileAuthenticated;
|
||||||
|
|
||||||
|
/* Backend Authentication state machine */
|
||||||
|
enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
|
||||||
|
BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
|
||||||
|
BE_AUTH_IGNORE
|
||||||
|
} be_auth_state;
|
||||||
|
/* constants */
|
||||||
|
unsigned int serverTimeout; /* default 30; 1..X */
|
||||||
|
#define BE_AUTH_DEFAULT_serverTimeout 30
|
||||||
|
/* counters */
|
||||||
|
Counter backendResponses;
|
||||||
|
Counter backendAccessChallenges;
|
||||||
|
Counter backendOtherRequestsToSupplicant;
|
||||||
|
Counter backendAuthSuccesses;
|
||||||
|
Counter backendAuthFails;
|
||||||
|
|
||||||
|
/* Reauthentication Timer state machine */
|
||||||
|
enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
|
||||||
|
} reauth_timer_state;
|
||||||
|
/* constants */
|
||||||
|
unsigned int reAuthPeriod; /* default 3600 s */
|
||||||
|
Boolean reAuthEnabled;
|
||||||
|
|
||||||
|
/* Authenticator Key Transmit state machine */
|
||||||
|
enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
|
||||||
|
} auth_key_tx_state;
|
||||||
|
|
||||||
|
/* Key Receive state machine */
|
||||||
|
enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
|
||||||
|
/* variables */
|
||||||
|
Boolean rxKey;
|
||||||
|
|
||||||
|
/* Controlled Directions state machine */
|
||||||
|
enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
|
||||||
|
/* variables */
|
||||||
|
ControlledDirection adminControlledDirections;
|
||||||
|
ControlledDirection operControlledDirections;
|
||||||
|
Boolean operEdge;
|
||||||
|
|
||||||
|
/* Authenticator Statistics Table */
|
||||||
|
Counter dot1xAuthEapolFramesRx;
|
||||||
|
Counter dot1xAuthEapolFramesTx;
|
||||||
|
Counter dot1xAuthEapolStartFramesRx;
|
||||||
|
Counter dot1xAuthEapolLogoffFramesRx;
|
||||||
|
Counter dot1xAuthEapolRespIdFramesRx;
|
||||||
|
Counter dot1xAuthEapolRespFramesRx;
|
||||||
|
Counter dot1xAuthEapolReqIdFramesTx;
|
||||||
|
Counter dot1xAuthEapolReqFramesTx;
|
||||||
|
Counter dot1xAuthInvalidEapolFramesRx;
|
||||||
|
Counter dot1xAuthEapLengthErrorFramesRx;
|
||||||
|
Counter dot1xAuthLastEapolFrameVersion;
|
||||||
|
|
||||||
|
/* Other variables - not defined in IEEE 802.1X */
|
||||||
|
u8 addr[ETH_ALEN]; /* Supplicant address */
|
||||||
|
#define EAPOL_SM_PREAUTH BIT(0)
|
||||||
|
#define EAPOL_SM_WAIT_START BIT(1)
|
||||||
|
int flags; /* EAPOL_SM_* */
|
||||||
|
|
||||||
|
/* EAPOL/AAA <-> EAP full authenticator interface */
|
||||||
|
struct eap_eapol_interface *eap_if;
|
||||||
|
|
||||||
|
int radius_identifier;
|
||||||
|
/* TODO: check when the last messages can be released */
|
||||||
|
struct radius_msg *last_recv_radius;
|
||||||
|
u8 last_eap_id; /* last used EAP Identifier */
|
||||||
|
u8 *identity;
|
||||||
|
size_t identity_len;
|
||||||
|
u8 eap_type_authsrv; /* EAP type of the last EAP packet from
|
||||||
|
* Authentication server */
|
||||||
|
u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
|
||||||
|
struct radius_class_data radius_class;
|
||||||
|
|
||||||
|
/* Keys for encrypting and signing EAPOL-Key frames */
|
||||||
|
u8 *eapol_key_sign;
|
||||||
|
size_t eapol_key_sign_len;
|
||||||
|
u8 *eapol_key_crypt;
|
||||||
|
size_t eapol_key_crypt_len;
|
||||||
|
|
||||||
|
struct eap_sm *eap;
|
||||||
|
|
||||||
|
Boolean initializing; /* in process of initializing state machines */
|
||||||
|
Boolean changed;
|
||||||
|
|
||||||
|
struct eapol_authenticator *eapol;
|
||||||
|
|
||||||
|
/* Somewhat nasty pointers to global hostapd and STA data to avoid
|
||||||
|
* passing these to every function */
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
struct sta_info *sta;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
|
||||||
|
struct eapol_auth_cb *cb);
|
||||||
|
void eapol_auth_deinit(struct eapol_authenticator *eapol);
|
||||||
|
struct eapol_state_machine *
|
||||||
|
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
|
||||||
|
int preauth, struct sta_info *sta);
|
||||||
|
void eapol_auth_free(struct eapol_state_machine *sm);
|
||||||
|
void eapol_auth_step(struct eapol_state_machine *sm);
|
||||||
|
void eapol_auth_initialize(struct eapol_state_machine *sm);
|
||||||
|
void eapol_auth_dump_state(FILE *f, const char *prefix,
|
||||||
|
struct eapol_state_machine *sm);
|
||||||
|
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
|
||||||
|
|
||||||
|
#endif /* EAPOL_SM_H */
|
216
hostapd/hostap_common.h
Normal file
216
hostapd/hostap_common.h
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Kernel driver communication with Linux Host AP driver
|
||||||
|
* Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HOSTAP_COMMON_H
|
||||||
|
#define HOSTAP_COMMON_H
|
||||||
|
|
||||||
|
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
|
||||||
|
|
||||||
|
/* New wireless extensions API - SET/GET convention (even ioctl numbers are
|
||||||
|
* root only)
|
||||||
|
*/
|
||||||
|
#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
|
||||||
|
#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
|
||||||
|
#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
|
||||||
|
#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
|
||||||
|
#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
|
||||||
|
#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
|
||||||
|
#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
|
||||||
|
#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
|
||||||
|
#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
|
||||||
|
#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
|
||||||
|
#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
|
||||||
|
#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
|
||||||
|
#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
|
||||||
|
#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
|
||||||
|
|
||||||
|
/* following are not in SIOCGIWPRIV list; check permission in the driver code
|
||||||
|
*/
|
||||||
|
#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
|
||||||
|
#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
|
||||||
|
|
||||||
|
|
||||||
|
/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
|
||||||
|
enum {
|
||||||
|
/* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
|
||||||
|
PRISM2_PARAM_TXRATECTRL = 2,
|
||||||
|
PRISM2_PARAM_BEACON_INT = 3,
|
||||||
|
PRISM2_PARAM_PSEUDO_IBSS = 4,
|
||||||
|
PRISM2_PARAM_ALC = 5,
|
||||||
|
/* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
|
||||||
|
PRISM2_PARAM_DUMP = 7,
|
||||||
|
PRISM2_PARAM_OTHER_AP_POLICY = 8,
|
||||||
|
PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
|
||||||
|
PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
|
||||||
|
PRISM2_PARAM_DTIM_PERIOD = 11,
|
||||||
|
PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
|
||||||
|
PRISM2_PARAM_MAX_WDS = 13,
|
||||||
|
PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
|
||||||
|
PRISM2_PARAM_AP_AUTH_ALGS = 15,
|
||||||
|
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
|
||||||
|
PRISM2_PARAM_HOST_ENCRYPT = 17,
|
||||||
|
PRISM2_PARAM_HOST_DECRYPT = 18,
|
||||||
|
PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
|
||||||
|
PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
|
||||||
|
PRISM2_PARAM_HOST_ROAMING = 21,
|
||||||
|
PRISM2_PARAM_BCRX_STA_KEY = 22,
|
||||||
|
PRISM2_PARAM_IEEE_802_1X = 23,
|
||||||
|
PRISM2_PARAM_ANTSEL_TX = 24,
|
||||||
|
PRISM2_PARAM_ANTSEL_RX = 25,
|
||||||
|
PRISM2_PARAM_MONITOR_TYPE = 26,
|
||||||
|
PRISM2_PARAM_WDS_TYPE = 27,
|
||||||
|
PRISM2_PARAM_HOSTSCAN = 28,
|
||||||
|
PRISM2_PARAM_AP_SCAN = 29,
|
||||||
|
PRISM2_PARAM_ENH_SEC = 30,
|
||||||
|
PRISM2_PARAM_IO_DEBUG = 31,
|
||||||
|
PRISM2_PARAM_BASIC_RATES = 32,
|
||||||
|
PRISM2_PARAM_OPER_RATES = 33,
|
||||||
|
PRISM2_PARAM_HOSTAPD = 34,
|
||||||
|
PRISM2_PARAM_HOSTAPD_STA = 35,
|
||||||
|
PRISM2_PARAM_WPA = 36,
|
||||||
|
PRISM2_PARAM_PRIVACY_INVOKED = 37,
|
||||||
|
PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
|
||||||
|
PRISM2_PARAM_DROP_UNENCRYPTED = 39,
|
||||||
|
PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
|
||||||
|
HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
|
||||||
|
|
||||||
|
|
||||||
|
/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
|
||||||
|
enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
|
||||||
|
AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
|
||||||
|
AP_MAC_CMD_KICKALL = 4 };
|
||||||
|
|
||||||
|
|
||||||
|
/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
|
||||||
|
enum {
|
||||||
|
PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
|
||||||
|
/* Note! Old versions of prism2_srec have a fatal error in CRC-16
|
||||||
|
* calculation, which will corrupt all non-volatile downloads.
|
||||||
|
* PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
|
||||||
|
* prevent use of old versions of prism2_srec for non-volatile
|
||||||
|
* download. */
|
||||||
|
PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
|
||||||
|
PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
|
||||||
|
/* Persistent versions of volatile download commands (keep firmware
|
||||||
|
* data in memory and automatically re-download after hw_reset */
|
||||||
|
PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
|
||||||
|
PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prism2_download_param {
|
||||||
|
u32 dl_cmd;
|
||||||
|
u32 start_addr;
|
||||||
|
u32 num_areas;
|
||||||
|
struct prism2_download_area {
|
||||||
|
u32 addr; /* wlan card address */
|
||||||
|
u32 len;
|
||||||
|
caddr_t ptr; /* pointer to data in user space */
|
||||||
|
} data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
|
||||||
|
#define PRISM2_MAX_DOWNLOAD_LEN 262144
|
||||||
|
|
||||||
|
|
||||||
|
/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
|
||||||
|
enum {
|
||||||
|
PRISM2_HOSTAPD_FLUSH = 1,
|
||||||
|
PRISM2_HOSTAPD_ADD_STA = 2,
|
||||||
|
PRISM2_HOSTAPD_REMOVE_STA = 3,
|
||||||
|
PRISM2_HOSTAPD_GET_INFO_STA = 4,
|
||||||
|
/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
|
||||||
|
PRISM2_SET_ENCRYPTION = 6,
|
||||||
|
PRISM2_GET_ENCRYPTION = 7,
|
||||||
|
PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
|
||||||
|
PRISM2_HOSTAPD_GET_RID = 9,
|
||||||
|
PRISM2_HOSTAPD_SET_RID = 10,
|
||||||
|
PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
|
||||||
|
PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
|
||||||
|
PRISM2_HOSTAPD_MLME = 13,
|
||||||
|
PRISM2_HOSTAPD_SCAN_REQ = 14,
|
||||||
|
PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
|
||||||
|
#define PRISM2_HOSTAPD_RID_HDR_LEN \
|
||||||
|
((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 */
|
59
hostapd/hostapd.8
Normal file
59
hostapd/hostapd.8
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd
|
||||||
|
.SH NAME
|
||||||
|
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B hostapd
|
||||||
|
[-hdBKtv] [-P <PID file>] <configuration file(s)>
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This manual page documents briefly the
|
||||||
|
.B hostapd
|
||||||
|
daemon.
|
||||||
|
.PP
|
||||||
|
.B hostapd
|
||||||
|
is a user space daemon for access point and authentication servers.
|
||||||
|
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||||
|
The current version supports Linux (Host AP, madwifi, Prism54 drivers) and FreeBSD (net80211).
|
||||||
|
|
||||||
|
.B hostapd
|
||||||
|
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
|
||||||
|
.B hostapd
|
||||||
|
supports separate frontend programs and an example text-based frontend,
|
||||||
|
.BR hostapd_cli ,
|
||||||
|
is included with
|
||||||
|
.BR hostapd .
|
||||||
|
.SH OPTIONS
|
||||||
|
A summary of options is included below.
|
||||||
|
For a complete description, run
|
||||||
|
.BR hostapd
|
||||||
|
from the command line.
|
||||||
|
.TP
|
||||||
|
.B \-h
|
||||||
|
Show usage.
|
||||||
|
.TP
|
||||||
|
.B \-d
|
||||||
|
Show more debug messages.
|
||||||
|
.TP
|
||||||
|
.B \-dd
|
||||||
|
Show even more debug messages.
|
||||||
|
.TP
|
||||||
|
.B \-B
|
||||||
|
Run daemon in the background.
|
||||||
|
.TP
|
||||||
|
.B \-P <PID file>
|
||||||
|
Path to PID file.
|
||||||
|
.TP
|
||||||
|
.B \-K
|
||||||
|
Include key data in debug messages.
|
||||||
|
.TP
|
||||||
|
.B \-t
|
||||||
|
Include timestamps in some debug messages.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Show hostapd version.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR hostapd_cli (1).
|
||||||
|
.SH AUTHOR
|
||||||
|
hostapd was written by Jouni Malinen <j@w1.fi>.
|
||||||
|
.PP
|
||||||
|
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||||
|
for the Debian project (but may be used by others).
|
5
hostapd/hostapd.accept
Normal file
5
hostapd/hostapd.accept
Normal file
|
@ -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
|
2000
hostapd/hostapd.c
Normal file
2000
hostapd/hostapd.c
Normal file
File diff suppressed because it is too large
Load diff
792
hostapd/hostapd.conf
Normal file
792
hostapd/hostapd.conf
Normal file
|
@ -0,0 +1,792 @@
|
||||||
|
##### hostapd configuration file ##############################################
|
||||||
|
# Empty lines and lines starting with # are ignored
|
||||||
|
|
||||||
|
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
|
||||||
|
# management frames); ath0 for madwifi
|
||||||
|
interface=wlan0
|
||||||
|
|
||||||
|
# In case of madwifi driver, an additional configuration parameter, bridge,
|
||||||
|
# must be used to notify hostapd if the interface is included in a bridge. This
|
||||||
|
# parameter is not used with Host AP driver.
|
||||||
|
#bridge=br0
|
||||||
|
|
||||||
|
# Driver interface type (hostap/wired/madwifi/prism54/test/nl80211/bsd);
|
||||||
|
# default: hostap)
|
||||||
|
# Use driver=test if building hostapd as a standalone RADIUS server that does
|
||||||
|
# not control any wireless/wired driver.
|
||||||
|
# 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
|
||||||
|
# bit 6 (64) = MLME
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Dump file for state information (on SIGUSR1)
|
||||||
|
dump_file=/tmp/hostapd.dump
|
||||||
|
|
||||||
|
# Interface for separate control program. If this is specified, hostapd
|
||||||
|
# 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 hostapd 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, hostapd 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
|
||||||
|
|
||||||
|
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
|
||||||
|
# Modify as needed to indicate country in which device is operating.
|
||||||
|
# This can limit available channels and transmit power.
|
||||||
|
# (default: US)
|
||||||
|
#country_code=US
|
||||||
|
|
||||||
|
# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
|
||||||
|
# channels and transmit power levels based on the regulatory limits. The
|
||||||
|
# country_code setting must be configured with the correct country for
|
||||||
|
# IEEE 802.11d functions.
|
||||||
|
# (default: 0 = disabled)
|
||||||
|
#ieee80211d=1
|
||||||
|
|
||||||
|
# Enable IEEE 802.11h. This enables the TPC and DFS services when operating
|
||||||
|
# in a regulatory domain which requires them. Once enabled it will be
|
||||||
|
# operational only when working in hw_mode a and in countries where it is
|
||||||
|
# required. The end user should not be allowed to disable this.
|
||||||
|
# The country_code setting must be configured with the correct country for
|
||||||
|
# IEEE 802.11h to function.
|
||||||
|
# When IEEE 802.11h is operational, the channel_policy and configured channel
|
||||||
|
# settings will be ignored but will behave as though the channel_policy is
|
||||||
|
# set to "3" (automatic channel selection). When IEEE 802.11h is enabled but
|
||||||
|
# not operational (for example, if the radio mode is changed from "a" to "b")
|
||||||
|
# the channel_policy and channel settings take effect again.
|
||||||
|
# (default: 1 = enabled)
|
||||||
|
#ieee80211h=1
|
||||||
|
|
||||||
|
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
|
||||||
|
# Default: IEEE 802.11b
|
||||||
|
hw_mode=a
|
||||||
|
|
||||||
|
# Channel number (IEEE 802.11)
|
||||||
|
# (default: 0, i.e., not set, used with channel_policy=2)
|
||||||
|
channel=60
|
||||||
|
|
||||||
|
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||||
|
beacon_int=100
|
||||||
|
|
||||||
|
# DTIM (delivery trafic information message) period (range 1..255):
|
||||||
|
# number of beacons between DTIMs (1 = every beacon includes DTIM element)
|
||||||
|
# (default: 2)
|
||||||
|
dtim_period=2
|
||||||
|
|
||||||
|
# Maximum number of stations allowed in station table. New stations will be
|
||||||
|
# rejected after the station table is full. IEEE 802.11 has a limit of 2007
|
||||||
|
# different association IDs, so this number should not be larger than that.
|
||||||
|
# (default: 2007)
|
||||||
|
max_num_sta=255
|
||||||
|
|
||||||
|
# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
|
||||||
|
# If this field is not included in hostapd.conf, hostapd will not control
|
||||||
|
# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
|
||||||
|
rts_threshold=2347
|
||||||
|
|
||||||
|
# Fragmentation threshold; 2346 = disabled (default); range 256..2346
|
||||||
|
# If this field is not included in hostapd.conf, hostapd will not control
|
||||||
|
# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
|
||||||
|
# it.
|
||||||
|
fragm_threshold=2346
|
||||||
|
|
||||||
|
# Rate configuration
|
||||||
|
# Default is to enable all rates supported by the hardware. This configuration
|
||||||
|
# item allows this list be filtered so that only the listed rates will be left
|
||||||
|
# in the list. If the list is empty, all rates are used. This list can have
|
||||||
|
# entries that are not in the list of rates the hardware supports (such entries
|
||||||
|
# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
|
||||||
|
# If this item is present, at least one rate have to be matching with the rates
|
||||||
|
# hardware supports.
|
||||||
|
# default: use the most common supported rate setting for the selected
|
||||||
|
# hw_mode (i.e., this line can be removed from configuration file in most
|
||||||
|
# cases)
|
||||||
|
#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
|
||||||
|
|
||||||
|
# Basic rate set configuration
|
||||||
|
# List of rates (in 100 kbps) that are included in the basic rate set.
|
||||||
|
# If this item is not included, usually reasonable default set is used.
|
||||||
|
#basic_rates=10 20
|
||||||
|
#basic_rates=10 20 55 110
|
||||||
|
#basic_rates=60 120 240
|
||||||
|
|
||||||
|
# Station MAC address -based authentication
|
||||||
|
# Please note that this kind of access control requires a driver that uses
|
||||||
|
# hostapd to take care of management frame processing and as such, this can be
|
||||||
|
# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Send empty SSID in beacons and ignore probe request frames that do not
|
||||||
|
# specify full SSID, i.e., require stations to know SSID.
|
||||||
|
# default: disabled (0)
|
||||||
|
# 1 = send empty (length=0) SSID in beacon and ignore probe request for
|
||||||
|
# broadcast SSID
|
||||||
|
# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
|
||||||
|
# with some clients that do not support empty SSID) and ignore probe
|
||||||
|
# requests for broadcast SSID
|
||||||
|
ignore_broadcast_ssid=0
|
||||||
|
|
||||||
|
# TX queue parameters (EDCF / bursting)
|
||||||
|
# default for all these fields: not set, use hardware defaults
|
||||||
|
# tx_queue_<queue name>_<param>
|
||||||
|
# queues: data0, data1, data2, data3, after_beacon, beacon
|
||||||
|
# (data0 is the highest priority queue)
|
||||||
|
# parameters:
|
||||||
|
# aifs: AIFS (default 2)
|
||||||
|
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
|
||||||
|
# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
|
||||||
|
# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
|
||||||
|
# bursting
|
||||||
|
#
|
||||||
|
# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
|
||||||
|
# These parameters are used by the access point when transmitting frames
|
||||||
|
# to the clients.
|
||||||
|
#
|
||||||
|
# Low priority / AC_BK = background
|
||||||
|
#tx_queue_data3_aifs=7
|
||||||
|
#tx_queue_data3_cwmin=15
|
||||||
|
#tx_queue_data3_cwmax=1023
|
||||||
|
#tx_queue_data3_burst=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
|
||||||
|
#
|
||||||
|
# Normal priority / AC_BE = best effort
|
||||||
|
#tx_queue_data2_aifs=3
|
||||||
|
#tx_queue_data2_cwmin=15
|
||||||
|
#tx_queue_data2_cwmax=63
|
||||||
|
#tx_queue_data2_burst=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
|
||||||
|
#
|
||||||
|
# High priority / AC_VI = video
|
||||||
|
#tx_queue_data1_aifs=1
|
||||||
|
#tx_queue_data1_cwmin=7
|
||||||
|
#tx_queue_data1_cwmax=15
|
||||||
|
#tx_queue_data1_burst=3.0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
|
||||||
|
#
|
||||||
|
# Highest priority / AC_VO = voice
|
||||||
|
#tx_queue_data0_aifs=1
|
||||||
|
#tx_queue_data0_cwmin=3
|
||||||
|
#tx_queue_data0_cwmax=7
|
||||||
|
#tx_queue_data0_burst=1.5
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
|
||||||
|
#
|
||||||
|
# Special queues; normally not user configurable
|
||||||
|
#
|
||||||
|
#tx_queue_after_beacon_aifs=2
|
||||||
|
#tx_queue_after_beacon_cwmin=15
|
||||||
|
#tx_queue_after_beacon_cwmax=1023
|
||||||
|
#tx_queue_after_beacon_burst=0
|
||||||
|
#
|
||||||
|
#tx_queue_beacon_aifs=2
|
||||||
|
#tx_queue_beacon_cwmin=3
|
||||||
|
#tx_queue_beacon_cwmax=7
|
||||||
|
#tx_queue_beacon_burst=1.5
|
||||||
|
|
||||||
|
# 802.1D Tag to AC mappings
|
||||||
|
# WMM specifies following mapping of data frames to different ACs. This mapping
|
||||||
|
# can be configured using Linux QoS/tc and sch_pktpri.o module.
|
||||||
|
# 802.1D Tag 802.1D Designation Access Category WMM Designation
|
||||||
|
# 1 BK AC_BK Background
|
||||||
|
# 2 - AC_BK Background
|
||||||
|
# 0 BE AC_BE Best Effort
|
||||||
|
# 3 EE AC_VI Video
|
||||||
|
# 4 CL AC_VI Video
|
||||||
|
# 5 VI AC_VI Video
|
||||||
|
# 6 VO AC_VO Voice
|
||||||
|
# 7 NC AC_VO Voice
|
||||||
|
# Data frames with no priority information: AC_BE
|
||||||
|
# Management frames: AC_VO
|
||||||
|
# PS-Poll frames: AC_BE
|
||||||
|
|
||||||
|
# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
|
||||||
|
# for 802.11a or 802.11g networks
|
||||||
|
# These parameters are sent to WMM clients when they associate.
|
||||||
|
# The parameters will be used by WMM clients for frames transmitted to the
|
||||||
|
# access point.
|
||||||
|
#
|
||||||
|
# note - txop_limit is in units of 32microseconds
|
||||||
|
# note - acm is admission control mandatory flag. 0 = admission control not
|
||||||
|
# required, 1 = mandatory
|
||||||
|
# note - here cwMin and cmMax are in exponent form. the actual cw value used
|
||||||
|
# will be (2^n)-1 where n is the value given here
|
||||||
|
#
|
||||||
|
wme_enabled=1
|
||||||
|
#
|
||||||
|
# Low priority / AC_BK = background
|
||||||
|
wme_ac_bk_cwmin=4
|
||||||
|
wme_ac_bk_cwmax=10
|
||||||
|
wme_ac_bk_aifs=7
|
||||||
|
wme_ac_bk_txop_limit=0
|
||||||
|
wme_ac_bk_acm=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
|
||||||
|
#
|
||||||
|
# Normal priority / AC_BE = best effort
|
||||||
|
wme_ac_be_aifs=3
|
||||||
|
wme_ac_be_cwmin=4
|
||||||
|
wme_ac_be_cwmax=10
|
||||||
|
wme_ac_be_txop_limit=0
|
||||||
|
wme_ac_be_acm=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
|
||||||
|
#
|
||||||
|
# High priority / AC_VI = video
|
||||||
|
wme_ac_vi_aifs=2
|
||||||
|
wme_ac_vi_cwmin=3
|
||||||
|
wme_ac_vi_cwmax=4
|
||||||
|
wme_ac_vi_txop_limit=94
|
||||||
|
wme_ac_vi_acm=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
|
||||||
|
#
|
||||||
|
# Highest priority / AC_VO = voice
|
||||||
|
wme_ac_vo_aifs=2
|
||||||
|
wme_ac_vo_cwmin=2
|
||||||
|
wme_ac_vo_cwmax=3
|
||||||
|
wme_ac_vo_txop_limit=47
|
||||||
|
wme_ac_vo_acm=0
|
||||||
|
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Static WEP key configuration
|
||||||
|
#
|
||||||
|
# The key number to use when transmitting.
|
||||||
|
# It must be between 0 and 3, and the corresponding key must be set.
|
||||||
|
# default: not set
|
||||||
|
#wep_default_key=0
|
||||||
|
# The WEP keys to use.
|
||||||
|
# A key may be a quoted string or unquoted hexadecimal digits.
|
||||||
|
# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
|
||||||
|
# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
|
||||||
|
# 128-bit (152-bit) WEP is used.
|
||||||
|
# Only the default key must be supplied; the others are optional.
|
||||||
|
# default: not set
|
||||||
|
#wep_key0=123456789a
|
||||||
|
#wep_key1="vwxyz"
|
||||||
|
#wep_key2=0102030405060708090a0b0c0d
|
||||||
|
#wep_key3=".2.4.6.8.0.23"
|
||||||
|
|
||||||
|
# Station inactivity limit
|
||||||
|
#
|
||||||
|
# If a station does not send anything in ap_max_inactivity seconds, an
|
||||||
|
# empty data frame is sent to it in order to verify whether it is
|
||||||
|
# still in range. If this frame is not ACKed, the station will be
|
||||||
|
# disassociated and then deauthenticated. This feature is used to
|
||||||
|
# clear station table of old entries when the STAs move out of the
|
||||||
|
# range.
|
||||||
|
#
|
||||||
|
# The station can associate again with the AP if it is still in range;
|
||||||
|
# this inactivity poll is just used as a nicer way of verifying
|
||||||
|
# inactivity; i.e., client will not report broken connection because
|
||||||
|
# disassociation frame is not sent immediately without first polling
|
||||||
|
# the STA with a data frame.
|
||||||
|
# default: 300 (i.e., 5 minutes)
|
||||||
|
#ap_max_inactivity=300
|
||||||
|
|
||||||
|
# Enable/disable internal bridge for packets between associated stations.
|
||||||
|
#
|
||||||
|
# When IEEE 802.11 is used in managed mode, packets are usually send through
|
||||||
|
# the AP even if they are from a wireless station to another wireless station.
|
||||||
|
# This functionality requires that the AP has a bridge functionality that sends
|
||||||
|
# frames back to the same interface if their destination is another associated
|
||||||
|
# station. In addition, broadcast/multicast frames from wireless stations will
|
||||||
|
# be sent both to the host system net stack (e.g., to eventually wired network)
|
||||||
|
# and back to the wireless interface.
|
||||||
|
#
|
||||||
|
# The internal bridge is implemented within the wireless kernel module and it
|
||||||
|
# bypasses kernel filtering (netfilter/iptables/ebtables). If direct
|
||||||
|
# communication between the stations needs to be prevented, the internal
|
||||||
|
# bridge can be disabled by setting bridge_packets=0.
|
||||||
|
#
|
||||||
|
# Note: If this variable is not included in hostapd.conf, hostapd does not
|
||||||
|
# change the configuration and iwpriv can be used to set the value with
|
||||||
|
# 'iwpriv wlan# param 10 0' command. If the variable is in hostapd.conf,
|
||||||
|
# hostapd will override possible iwpriv configuration whenever configuration
|
||||||
|
# file is reloaded.
|
||||||
|
#
|
||||||
|
# default: do not control from hostapd (80211.o defaults to 1=enabled)
|
||||||
|
#bridge_packets=1
|
||||||
|
|
||||||
|
|
||||||
|
##### IEEE 802.1X-2004 related configuration ##################################
|
||||||
|
|
||||||
|
# Require IEEE 802.1X authorization
|
||||||
|
#ieee8021x=1
|
||||||
|
|
||||||
|
# IEEE 802.1X/EAPOL version
|
||||||
|
# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
|
||||||
|
# version 2. However, there are many client implementations that do not handle
|
||||||
|
# the new version number correctly (they seem to drop the frames completely).
|
||||||
|
# In order to make hostapd interoperate with these clients, the version number
|
||||||
|
# can be set to the older version (1) with this configuration value.
|
||||||
|
#eapol_version=2
|
||||||
|
|
||||||
|
# Optional displayable message sent with EAP Request-Identity. The first \0
|
||||||
|
# in this string will be converted to ASCII-0 (nul). This can be used to
|
||||||
|
# separate network info (comma separated list of attribute=value pairs); see,
|
||||||
|
# e.g., RFC 4284.
|
||||||
|
#eap_message=hello
|
||||||
|
#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
|
||||||
|
# address when sending EAPOL frames with driver=wired. This is the most common
|
||||||
|
# mechanism used in wired authentication, but it also requires that the port
|
||||||
|
# is only used by one station.
|
||||||
|
#use_pae_group_addr=1
|
||||||
|
|
||||||
|
##### Integrated EAP server ###################################################
|
||||||
|
|
||||||
|
# Optionally, hostapd can be configured to use an integrated EAP server
|
||||||
|
# to process EAP authentication locally without need for an external RADIUS
|
||||||
|
# server. This functionality can be used both as a local authentication server
|
||||||
|
# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
|
||||||
|
|
||||||
|
# Use integrated EAP server instead of external RADIUS authentication
|
||||||
|
# server. This is also needed if hostapd is configured to act as a RADIUS
|
||||||
|
# authentication server.
|
||||||
|
eap_server=0
|
||||||
|
|
||||||
|
# Path for EAP server 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
|
||||||
|
|
||||||
|
# Enable CRL verification.
|
||||||
|
# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
|
||||||
|
# valid CRL signed by the CA is required to be included in the ca_cert file.
|
||||||
|
# This can be done by using PEM format for CA certificate and CRL and
|
||||||
|
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
|
||||||
|
# restarted to take the new CRL into use.
|
||||||
|
# 0 = do not verify CRLs (default)
|
||||||
|
# 1 = check the CRL of the user certificate
|
||||||
|
# 2 = check all CRLs in the certificate path
|
||||||
|
#check_crl=1
|
||||||
|
|
||||||
|
# dh_file: File path to DH/DSA parameters file (in PEM format)
|
||||||
|
# This is an optional configuration file for setting parameters for an
|
||||||
|
# ephemeral DH key exchange. In most cases, the default RSA authentication does
|
||||||
|
# not use this configuration. However, it is possible setup RSA to use
|
||||||
|
# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
|
||||||
|
# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
|
||||||
|
# is in DSA parameters format, it will be automatically converted into DH
|
||||||
|
# params. This parameter is required if anonymous EAP-FAST is used.
|
||||||
|
#dh_file=/etc/hostapd.dh.pem
|
||||||
|
|
||||||
|
# Configuration data for EAP-SIM database/authentication gateway interface.
|
||||||
|
# This is a text string in implementation specific format. The example
|
||||||
|
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
|
||||||
|
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
|
||||||
|
# prefix.
|
||||||
|
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
|
||||||
|
|
||||||
|
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
|
||||||
|
# random value. It is configured as a 16-octet value in hex format. It can be
|
||||||
|
# generated, e.g., with the following command:
|
||||||
|
# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
|
||||||
|
#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
|
||||||
|
|
||||||
|
# EAP-FAST authority identity (A-ID)
|
||||||
|
#eap_fast_a_id=test server
|
||||||
|
|
||||||
|
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
|
||||||
|
# (default: 0 = disabled).
|
||||||
|
#eap_sim_aka_result_ind=1
|
||||||
|
|
||||||
|
|
||||||
|
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
|
||||||
|
|
||||||
|
# Interface to be used for IAPP broadcast packets
|
||||||
|
#iapp_interface=eth0
|
||||||
|
|
||||||
|
|
||||||
|
##### RADIUS client 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.
|
||||||
|
# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
|
||||||
|
# 48 octets long.
|
||||||
|
#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
|
||||||
|
|
||||||
|
# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
|
||||||
|
# is used for the stations. This information is parsed from following RADIUS
|
||||||
|
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
|
||||||
|
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
|
||||||
|
# VLANID as a string). vlan_file option below must be configured if dynamic
|
||||||
|
# VLANs are used.
|
||||||
|
# 0 = disabled (default)
|
||||||
|
# 1 = option; use default interface if RADIUS server does not include VLAN ID
|
||||||
|
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
|
||||||
|
#dynamic_vlan=0
|
||||||
|
|
||||||
|
# VLAN interface list for dynamic VLAN mode is read from a separate text file.
|
||||||
|
# This list is used to map VLAN ID from the RADIUS server to a network
|
||||||
|
# interface. Each station is bound to one interface in the same way as with
|
||||||
|
# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
|
||||||
|
# interface and the line must include VLAN ID and interface name separated by
|
||||||
|
# white space (space or tab).
|
||||||
|
#vlan_file=/etc/hostapd.vlan
|
||||||
|
|
||||||
|
# Interface where 802.1q tagged packets should appear when a RADIUS server is
|
||||||
|
# used to determine which VLAN a station is on. hostapd creates a bridge for
|
||||||
|
# each VLAN. Then hostapd adds a VLAN interface (associated with the interface
|
||||||
|
# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
|
||||||
|
# to the bridge.
|
||||||
|
#vlan_tagged_interface=eth0
|
||||||
|
|
||||||
|
|
||||||
|
##### RADIUS authentication server configuration ##############################
|
||||||
|
|
||||||
|
# hostapd can be used as a RADIUS authentication server for other hosts. This
|
||||||
|
# requires that the integrated EAP server 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
|
||||||
|
|
||||||
|
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
|
||||||
|
#radius_server_ipv6=1
|
||||||
|
|
||||||
|
|
||||||
|
##### 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)
|
||||||
|
# Pairwise cipher for WPA (v1) (default: TKIP)
|
||||||
|
#wpa_pairwise=TKIP CCMP
|
||||||
|
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
|
||||||
|
#rsn_pairwise=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
|
||||||
|
|
||||||
|
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
|
||||||
|
# allowed. This is only used with RSN/WPA2.
|
||||||
|
# 0 = disabled (default)
|
||||||
|
# 1 = enabled
|
||||||
|
#peerkey=1
|
||||||
|
|
||||||
|
# ieee80211w: Whether management frame protection is enabled
|
||||||
|
# 0 = disabled (default)
|
||||||
|
# 1 = optional
|
||||||
|
# 2 = required
|
||||||
|
#ieee80211w=0
|
||||||
|
|
||||||
|
|
||||||
|
##### IEEE 802.11r configuration ##############################################
|
||||||
|
|
||||||
|
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||||
|
# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
|
||||||
|
# same SSID) between which a STA can use Fast BSS Transition.
|
||||||
|
# 2-octet identifier as a hex string.
|
||||||
|
#mobility_domain=a1b2
|
||||||
|
|
||||||
|
# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
|
||||||
|
# 1 to 48 octet identifier.
|
||||||
|
# This is configured with nas_identifier (see RADIUS client section above).
|
||||||
|
|
||||||
|
# Default lifetime of the PMK-RO in minutes; range 1..65535
|
||||||
|
# (dot11FTR0KeyLifetime)
|
||||||
|
#r0_key_lifetime=10000
|
||||||
|
|
||||||
|
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
|
||||||
|
# 6-octet identifier as a hex string.
|
||||||
|
#r1_key_holder=000102030405
|
||||||
|
|
||||||
|
# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
|
||||||
|
# (dot11FTReassociationDeadline)
|
||||||
|
#reassociation_deadline=1000
|
||||||
|
|
||||||
|
# List of R0KHs in the same Mobility Domain
|
||||||
|
# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
|
||||||
|
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
|
||||||
|
# address when requesting PMK-R1 key from the R0KH that the STA used during the
|
||||||
|
# Initial Mobility Domain Association.
|
||||||
|
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
|
||||||
|
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
|
||||||
|
# And so on.. One line per R0KH.
|
||||||
|
|
||||||
|
# List of R1KHs in the same Mobility Domain
|
||||||
|
# format: <MAC address> <R0KH-ID> <128-bit key as hex string>
|
||||||
|
# This list is used to map R1KH-ID to a destination MAC address when sending
|
||||||
|
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
|
||||||
|
# that can request PMK-R1 keys.
|
||||||
|
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
|
||||||
|
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
|
||||||
|
# And so on.. One line per R1KH.
|
||||||
|
|
||||||
|
# Whether PMK-R1 push is enabled at R0KH
|
||||||
|
# 0 = do not push PMK-R1 to all configured R1KHs (default)
|
||||||
|
# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
|
||||||
|
#pmk_r1_push=1
|
||||||
|
|
||||||
|
##### Passive scanning ########################################################
|
||||||
|
# Scan different channels every N seconds. 0 = disable passive scanning.
|
||||||
|
#passive_scan_interval=60
|
||||||
|
|
||||||
|
# Listen N usecs on each channel when doing passive scanning.
|
||||||
|
# This value plus the time needed for changing channels should be less than
|
||||||
|
# 32 milliseconds (i.e. 32000 usec) to avoid interruptions to normal
|
||||||
|
# operations. Time needed for channel changing varies based on the used wlan
|
||||||
|
# hardware.
|
||||||
|
# default: disabled (0)
|
||||||
|
#passive_scan_listen=10000
|
||||||
|
|
||||||
|
# Passive scanning mode:
|
||||||
|
# 0 = scan all supported modes (802.11a/b/g/Turbo) (default)
|
||||||
|
# 1 = scan only the mode that is currently used for normal operations
|
||||||
|
#passive_scan_mode=1
|
||||||
|
|
||||||
|
# Maximum number of entries kept in AP table (either for passive scanning or
|
||||||
|
# for detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||||
|
# removed when adding a new entry that would make the list grow over this
|
||||||
|
# limit. Note! Wi-Fi certification for IEEE 802.11g requires that OLBC is
|
||||||
|
# enabled, so this field should not be set to 0 when using IEEE 802.11g.
|
||||||
|
# default: 255
|
||||||
|
#ap_table_max_size=255
|
||||||
|
|
||||||
|
# Number of seconds of no frames received after which entries may be deleted
|
||||||
|
# from the AP table. Since passive scanning is not usually performed frequently
|
||||||
|
# this should not be set to very small value. In addition, there is no
|
||||||
|
# guarantee that every scan cycle will receive beacon frames from the
|
||||||
|
# neighboring APs.
|
||||||
|
# default: 60
|
||||||
|
#ap_table_expiration_time=3600
|
||||||
|
|
||||||
|
|
||||||
|
##### Multiple BSSID support ##################################################
|
||||||
|
#
|
||||||
|
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
|
||||||
|
# interfaces). Other BSSIDs can be added by using separator 'bss' with
|
||||||
|
# default interface name to be allocated for the data packets of the new BSS.
|
||||||
|
#
|
||||||
|
# hostapd will generate BSSID mask based on the BSSIDs that are
|
||||||
|
# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
|
||||||
|
# not the case, the MAC address of the radio must be changed before starting
|
||||||
|
# hostapd (ifconfig wlan0 hw ether <MAC addr>).
|
||||||
|
#
|
||||||
|
# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
|
||||||
|
# specified using the 'bssid' parameter.
|
||||||
|
# If an explicit BSSID is specified, it must be chosen such that it:
|
||||||
|
# - results in a valid MASK that covers it and the dev_addr
|
||||||
|
# - is not the same as the MAC address of the radio
|
||||||
|
# - is not the same as any other explicitly specified BSSID
|
||||||
|
#
|
||||||
|
# Please note that hostapd uses some of the values configured for the first BSS
|
||||||
|
# as the defaults for the following BSSes. However, it is recommended that all
|
||||||
|
# BSSes include explicit configuration of all relevant configuration items.
|
||||||
|
#
|
||||||
|
#bss=wlan0_0
|
||||||
|
#ssid=test2
|
||||||
|
# most of the above items can be used here (apart from radio interface specific
|
||||||
|
# items, like channel)
|
||||||
|
|
||||||
|
#bss=wlan0_1
|
||||||
|
#bssid=00:13:10:95:fe:0b
|
||||||
|
# ...
|
5
hostapd/hostapd.deny
Normal file
5
hostapd/hostapd.deny
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
|
||||||
|
# with the AP.
|
||||||
|
00:20:30:40:50:60
|
||||||
|
00:ab:cd:ef:12:34
|
||||||
|
00:00:30:40:50:60
|
91
hostapd/hostapd.eap_user
Normal file
91
hostapd/hostapd.eap_user
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
# hostapd user database for integrated EAP server
|
||||||
|
|
||||||
|
# Each line must contain an identity, EAP method(s), and an optional password
|
||||||
|
# separated with whitespace (space or tab). The identity and password must be
|
||||||
|
# double quoted ("user"). Password can alternatively be stored as
|
||||||
|
# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
|
||||||
|
# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
|
||||||
|
# that the plaintext password does not need to be included in the user file.
|
||||||
|
# Password hash is stored as hash:<16-octets of hex data> without quotation
|
||||||
|
# marks.
|
||||||
|
|
||||||
|
# [2] flag in the end of the line can be used to mark users for tunneled phase
|
||||||
|
# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
|
||||||
|
# identity can be used in the unencrypted phase 1 and the real user identity
|
||||||
|
# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
|
||||||
|
# access is needed, two user entries is needed, one for phase 1 and another
|
||||||
|
# with the same username for phase 2.
|
||||||
|
#
|
||||||
|
# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
|
||||||
|
# password option.
|
||||||
|
# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
|
||||||
|
# password.
|
||||||
|
# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
|
||||||
|
#
|
||||||
|
# * can be used as a wildcard to match any user identity. The main purposes for
|
||||||
|
# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
|
||||||
|
# avoid having to configure every certificate for EAP-TLS authentication. The
|
||||||
|
# first matching entry is selected, so * should be used as the last phase 1
|
||||||
|
# user entry.
|
||||||
|
#
|
||||||
|
# "prefix"* can be used to match the given prefix and anything after this. The
|
||||||
|
# main purpose for this is to be able to avoid EAP method negotiation when the
|
||||||
|
# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
|
||||||
|
# is only allowed for phase 1 identities.
|
||||||
|
#
|
||||||
|
# Multiple methods can be configured to make the authenticator try them one by
|
||||||
|
# one until the peer accepts one. The method names are separated with a
|
||||||
|
# comma (,).
|
||||||
|
#
|
||||||
|
# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
|
||||||
|
# version based on the Phase 1 identity. Without this flag, the EAP
|
||||||
|
# authenticator advertises the highest supported version and select the version
|
||||||
|
# based on the first PEAP packet from the supplicant.
|
||||||
|
#
|
||||||
|
# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
|
||||||
|
# Tunneled EAP methods are configured with standard EAP method name and [2]
|
||||||
|
# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
|
||||||
|
# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
|
||||||
|
# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
|
||||||
|
# hash.
|
||||||
|
|
||||||
|
# Phase 1 users
|
||||||
|
"user" MD5 "password"
|
||||||
|
"test user" MD5 "secret"
|
||||||
|
"example user" TLS
|
||||||
|
"DOMAIN\user" MSCHAPV2 "password"
|
||||||
|
"gtc user" GTC "password"
|
||||||
|
"pax user" PAX "unknown"
|
||||||
|
"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef
|
||||||
|
"psk user" PSK "unknown"
|
||||||
|
"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef
|
||||||
|
"sake.user@example.com" SAKE 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||||
|
"ttls" TTLS
|
||||||
|
"not anonymous" PEAP
|
||||||
|
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
|
||||||
|
"0"* AKA,TTLS,TLS,PEAP,SIM
|
||||||
|
"1"* SIM,TTLS,TLS,PEAP,AKA
|
||||||
|
"2"* AKA,TTLS,TLS,PEAP,SIM
|
||||||
|
"3"* SIM,TTLS,TLS,PEAP,AKA
|
||||||
|
"4"* AKA,TTLS,TLS,PEAP,SIM
|
||||||
|
"5"* SIM,TTLS,TLS,PEAP,AKA
|
||||||
|
|
||||||
|
# Wildcard for all other identities
|
||||||
|
* PEAP,TTLS,TLS,SIM,AKA
|
||||||
|
|
||||||
|
# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
|
||||||
|
"t-md5" MD5 "password" [2]
|
||||||
|
"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2]
|
||||||
|
"t-gtc" GTC "password" [2]
|
||||||
|
"not anonymous" MSCHAPV2 "password" [2]
|
||||||
|
"user" MD5,GTC,MSCHAPV2 "password" [2]
|
||||||
|
"test user" MSCHAPV2 hash:000102030405060708090a0b0c0d0e0f [2]
|
||||||
|
"ttls-user" TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2 "password" [2]
|
||||||
|
|
||||||
|
# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
|
||||||
|
"0"* AKA [2]
|
||||||
|
"1"* SIM [2]
|
||||||
|
"2"* AKA [2]
|
||||||
|
"3"* SIM [2]
|
||||||
|
"4"* AKA [2]
|
||||||
|
"5"* SIM [2]
|
239
hostapd/hostapd.h
Normal file
239
hostapd/hostapd.h
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Initialization and configuration
|
||||||
|
* Host AP kernel driver
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HOSTAPD_H
|
||||||
|
#define HOSTAPD_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "ap.h"
|
||||||
|
|
||||||
|
#ifndef ETH_ALEN
|
||||||
|
#define ETH_ALEN 6
|
||||||
|
#endif
|
||||||
|
#ifndef IFNAMSIZ
|
||||||
|
#define IFNAMSIZ 16
|
||||||
|
#endif
|
||||||
|
#ifndef ETH_P_ALL
|
||||||
|
#define ETH_P_ALL 0x0003
|
||||||
|
#endif
|
||||||
|
#ifndef ETH_P_PAE
|
||||||
|
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||||
|
#endif /* ETH_P_PAE */
|
||||||
|
#ifndef ETH_P_EAPOL
|
||||||
|
#define ETH_P_EAPOL ETH_P_PAE
|
||||||
|
#endif /* ETH_P_EAPOL */
|
||||||
|
|
||||||
|
#ifndef ETH_P_RRB
|
||||||
|
#define ETH_P_RRB 0x890D
|
||||||
|
#endif /* ETH_P_RRB */
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
#define MAX_VLAN_ID 4094
|
||||||
|
|
||||||
|
struct ieee8023_hdr {
|
||||||
|
u8 dest[6];
|
||||||
|
u8 src[6];
|
||||||
|
u16 ethertype;
|
||||||
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
|
|
||||||
|
struct ieee80211_hdr {
|
||||||
|
le16 frame_control;
|
||||||
|
le16 duration_id;
|
||||||
|
u8 addr1[6];
|
||||||
|
u8 addr2[6];
|
||||||
|
u8 addr3[6];
|
||||||
|
le16 seq_ctrl;
|
||||||
|
/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
|
||||||
|
*/
|
||||||
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
#define IEEE80211_DA_FROMDS addr1
|
||||||
|
#define IEEE80211_BSSID_FROMDS addr2
|
||||||
|
#define IEEE80211_SA_FROMDS addr3
|
||||||
|
|
||||||
|
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
|
||||||
|
|
||||||
|
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
|
||||||
|
|
||||||
|
/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
|
||||||
|
* frames that might be longer than normal default MTU and they are not
|
||||||
|
* fragmented */
|
||||||
|
#define HOSTAPD_MTU 2290
|
||||||
|
|
||||||
|
extern unsigned char rfc1042_header[6];
|
||||||
|
|
||||||
|
struct hostap_sta_driver_data {
|
||||||
|
unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
|
||||||
|
unsigned long current_tx_rate;
|
||||||
|
unsigned long inactive_msec;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned long num_ps_buf_frames;
|
||||||
|
unsigned long tx_retry_failed;
|
||||||
|
unsigned long tx_retry_count;
|
||||||
|
int last_rssi;
|
||||||
|
int last_ack_rssi;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wpa_driver_ops;
|
||||||
|
struct wpa_ctrl_dst;
|
||||||
|
struct radius_server_data;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
struct full_dynamic_vlan;
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hostapd_data - hostapd per-BSS data structure
|
||||||
|
*/
|
||||||
|
struct hostapd_data {
|
||||||
|
struct hostapd_iface *iface;
|
||||||
|
struct hostapd_config *iconf;
|
||||||
|
struct hostapd_bss_config *conf;
|
||||||
|
int interface_added; /* virtual interface added for this BSS */
|
||||||
|
|
||||||
|
u8 own_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
int num_sta; /* number of entries in sta_list */
|
||||||
|
struct sta_info *sta_list; /* STA info list head */
|
||||||
|
struct sta_info *sta_hash[STA_HASH_SIZE];
|
||||||
|
|
||||||
|
/* pointers to STA info; based on allocated AID or NULL if AID free
|
||||||
|
* AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
|
||||||
|
* and so on
|
||||||
|
*/
|
||||||
|
struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
|
||||||
|
|
||||||
|
const struct wpa_driver_ops *driver;
|
||||||
|
void *drv_priv;
|
||||||
|
|
||||||
|
u8 *default_wep_key;
|
||||||
|
u8 default_wep_key_idx;
|
||||||
|
|
||||||
|
struct radius_client_data *radius;
|
||||||
|
int radius_client_reconfigured;
|
||||||
|
u32 acct_session_id_hi, acct_session_id_lo;
|
||||||
|
|
||||||
|
struct iapp_data *iapp;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
struct wpa_authenticator *wpa_auth;
|
||||||
|
struct eapol_authenticator *eapol_auth;
|
||||||
|
|
||||||
|
struct rsn_preauth_interface *preauth_iface;
|
||||||
|
time_t michael_mic_failure;
|
||||||
|
int michael_mic_failures;
|
||||||
|
int tkip_countermeasures;
|
||||||
|
|
||||||
|
int ctrl_sock;
|
||||||
|
struct wpa_ctrl_dst *ctrl_dst;
|
||||||
|
|
||||||
|
void *ssl_ctx;
|
||||||
|
void *eap_sim_db_priv;
|
||||||
|
struct radius_server_data *radius_srv;
|
||||||
|
|
||||||
|
int parameter_set_count;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
struct full_dynamic_vlan *full_dynamic_vlan;
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
struct l2_packet_data *l2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_iface_cb - Generic callback type for per-iface asynchronous requests
|
||||||
|
* @iface: the interface the event occured on.
|
||||||
|
* @status: 0 if the request succeeded; -1 if the request failed.
|
||||||
|
*/
|
||||||
|
typedef void (*hostapd_iface_cb)(struct hostapd_iface *iface, int status);
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_config_change;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hostapd_iface - hostapd per-interface data structure
|
||||||
|
*/
|
||||||
|
struct hostapd_iface {
|
||||||
|
char *config_fname;
|
||||||
|
struct hostapd_config *conf;
|
||||||
|
|
||||||
|
hostapd_iface_cb setup_cb;
|
||||||
|
|
||||||
|
size_t num_bss;
|
||||||
|
struct hostapd_data **bss;
|
||||||
|
|
||||||
|
int num_ap; /* number of entries in ap_list */
|
||||||
|
struct ap_info *ap_list; /* AP info list head */
|
||||||
|
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||||
|
struct ap_info *ap_iter_list;
|
||||||
|
|
||||||
|
struct hostapd_hw_modes *hw_features;
|
||||||
|
int num_hw_features;
|
||||||
|
struct hostapd_hw_modes *current_mode;
|
||||||
|
/* Rates that are currently used (i.e., filtered copy of
|
||||||
|
* current_mode->channels */
|
||||||
|
int num_rates;
|
||||||
|
struct hostapd_rate_data *current_rates;
|
||||||
|
hostapd_iface_cb hw_mode_sel_cb;
|
||||||
|
|
||||||
|
u16 hw_flags;
|
||||||
|
|
||||||
|
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
|
||||||
|
* in 802.11g BSS) */
|
||||||
|
int num_sta_non_erp;
|
||||||
|
|
||||||
|
/* Number of associated stations that do not support Short Slot Time */
|
||||||
|
int num_sta_no_short_slot_time;
|
||||||
|
|
||||||
|
/* Number of associated stations that do not support Short Preamble */
|
||||||
|
int num_sta_no_short_preamble;
|
||||||
|
|
||||||
|
int olbc; /* Overlapping Legacy BSS Condition */
|
||||||
|
|
||||||
|
int dfs_enable;
|
||||||
|
u8 pwr_const;
|
||||||
|
unsigned int tx_power;
|
||||||
|
unsigned int sta_max_power;
|
||||||
|
|
||||||
|
unsigned int channel_switch;
|
||||||
|
|
||||||
|
struct hostapd_config_change *change;
|
||||||
|
hostapd_iface_cb reload_iface_cb;
|
||||||
|
hostapd_iface_cb config_reload_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int reassoc);
|
||||||
|
|
||||||
|
#endif /* HOSTAPD_H */
|
4
hostapd/hostapd.radius_clients
Normal file
4
hostapd/hostapd.radius_clients
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# RADIUS client configuration for the RADIUS server
|
||||||
|
10.1.2.3 secret passphrase
|
||||||
|
192.168.1.0/24 another very secret passphrase
|
||||||
|
0.0.0.0/0 radius
|
9
hostapd/hostapd.sim_db
Normal file
9
hostapd/hostapd.sim_db
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Example GSM authentication triplet file for EAP-SIM authenticator
|
||||||
|
# IMSI:Kc:SRES:RAND
|
||||||
|
# IMSI: ASCII string (numbers)
|
||||||
|
# Kc: hex, 8 octets
|
||||||
|
# SRES: hex, 4 octets
|
||||||
|
# RAND: hex, 16 octets
|
||||||
|
234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||||
|
234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
|
9
hostapd/hostapd.vlan
Normal file
9
hostapd/hostapd.vlan
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# VLAN ID to network interface mapping
|
||||||
|
1 vlan1
|
||||||
|
2 vlan2
|
||||||
|
3 vlan3
|
||||||
|
100 guest
|
||||||
|
# Optional wildcard entry matching all VLAN IDs. The first # in the interface
|
||||||
|
# name will be replaced with the VLAN ID. The network interfaces are created
|
||||||
|
# (and removed) dynamically based on the use.
|
||||||
|
* vlan#
|
9
hostapd/hostapd.wpa_psk
Normal file
9
hostapd/hostapd.wpa_psk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# List of WPA PSKs. Each line, except for empty lines and lines starting
|
||||||
|
# with #, must contain a MAC address and PSK separated with a space.
|
||||||
|
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
|
||||||
|
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
|
||||||
|
# characters or as a 256-bit hex PSK (64 hex digits).
|
||||||
|
00:00:00:00:00:00 secret passphrase
|
||||||
|
00:11:22:33:44:55 another passphrase
|
||||||
|
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||||
|
00:00:00:00:00:00 another passphrase for all STAs
|
83
hostapd/hostapd_cli.1
Normal file
83
hostapd/hostapd_cli.1
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface"
|
||||||
|
.SH NAME
|
||||||
|
hostapd_cli \- hostapd command-line interface
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B hostapd_cli
|
||||||
|
[-p<path>] [-i<ifname>] [-hv] [command..]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
This manual page documents briefly the
|
||||||
|
.B hostapd_cli
|
||||||
|
utility.
|
||||||
|
.PP
|
||||||
|
.B hostapd_cli
|
||||||
|
is a command-line interface for the
|
||||||
|
.B hostapd
|
||||||
|
daemon.
|
||||||
|
|
||||||
|
.B hostapd
|
||||||
|
is a user space daemon for access point and authentication servers.
|
||||||
|
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
|
||||||
|
For more information about
|
||||||
|
.B hostapd
|
||||||
|
refer to the
|
||||||
|
.BR hostapd (8)
|
||||||
|
man page.
|
||||||
|
.SH OPTIONS
|
||||||
|
A summary of options is included below.
|
||||||
|
For a complete description, run
|
||||||
|
.BR hostapd_cli
|
||||||
|
from the command line.
|
||||||
|
.TP
|
||||||
|
.B \-p<path>
|
||||||
|
Path to find control sockets.
|
||||||
|
|
||||||
|
Default: /var/run/hostapd
|
||||||
|
.TP
|
||||||
|
.B \-i<ifname>
|
||||||
|
Interface to listen on.
|
||||||
|
|
||||||
|
Default: first interface found in socket path.
|
||||||
|
.TP
|
||||||
|
.B \-h
|
||||||
|
Show usage.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Show hostapd_cli version.
|
||||||
|
.SH COMMANDS
|
||||||
|
A summary of commands is included below.
|
||||||
|
For a complete description, run
|
||||||
|
.BR hostapd_cli
|
||||||
|
from the command line.
|
||||||
|
.TP
|
||||||
|
.B mib
|
||||||
|
Get MIB variables (dot1x, dot11, radius).
|
||||||
|
.TP
|
||||||
|
.B sta <addr>
|
||||||
|
Get MIB variables for one station.
|
||||||
|
.TP
|
||||||
|
.B all_sta
|
||||||
|
Get MIB variables for all stations.
|
||||||
|
.TP
|
||||||
|
.B help
|
||||||
|
Get usage help.
|
||||||
|
.TP
|
||||||
|
.B interface [ifname]
|
||||||
|
Show interfaces/select interface.
|
||||||
|
.TP
|
||||||
|
.B level <debug level>
|
||||||
|
Change debug level.
|
||||||
|
.TP
|
||||||
|
.B license
|
||||||
|
Show full
|
||||||
|
.B hostapd_cli
|
||||||
|
license.
|
||||||
|
.TP
|
||||||
|
.B quit
|
||||||
|
Exit hostapd_cli.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR hostapd (8).
|
||||||
|
.SH AUTHOR
|
||||||
|
hostapd_cli was written by Jouni Malinen <j@w1.fi>.
|
||||||
|
.PP
|
||||||
|
This manual page was written by Faidon Liambotis <faidon@cube.gr>,
|
||||||
|
for the Debian project (but may be used by others).
|
615
hostapd/hostapd_cli.c
Normal file
615
hostapd/hostapd_cli.c
Normal file
|
@ -0,0 +1,615 @@
|
||||||
|
/*
|
||||||
|
* hostapd - command line interface for hostapd daemon
|
||||||
|
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include "wpa_ctrl.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const char *hostapd_cli_version =
|
||||||
|
"hostapd_cli v" VERSION_STR "\n"
|
||||||
|
"Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> and contributors";
|
||||||
|
|
||||||
|
|
||||||
|
static const char *hostapd_cli_license =
|
||||||
|
"This program is free software. You can distribute it and/or modify it\n"
|
||||||
|
"under the terms of the GNU General Public License version 2.\n"
|
||||||
|
"\n"
|
||||||
|
"Alternatively, this software may be distributed under the terms of the\n"
|
||||||
|
"BSD license. See README and COPYING for more details.\n";
|
||||||
|
|
||||||
|
static const char *hostapd_cli_full_license =
|
||||||
|
"This program is free software; you can redistribute it and/or modify\n"
|
||||||
|
"it under the terms of the GNU General Public License version 2 as\n"
|
||||||
|
"published by the Free Software Foundation.\n"
|
||||||
|
"\n"
|
||||||
|
"This program is distributed in the hope that it will be useful,\n"
|
||||||
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||||
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||||
|
"GNU General Public License for more details.\n"
|
||||||
|
"\n"
|
||||||
|
"You should have received a copy of the GNU General Public License\n"
|
||||||
|
"along with this program; if not, write to the Free Software\n"
|
||||||
|
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
|
||||||
|
"\n"
|
||||||
|
"Alternatively, this software may be distributed under the terms of the\n"
|
||||||
|
"BSD license.\n"
|
||||||
|
"\n"
|
||||||
|
"Redistribution and use in source and binary forms, with or without\n"
|
||||||
|
"modification, are permitted provided that the following conditions are\n"
|
||||||
|
"met:\n"
|
||||||
|
"\n"
|
||||||
|
"1. Redistributions of source code must retain the above copyright\n"
|
||||||
|
" notice, this list of conditions and the following disclaimer.\n"
|
||||||
|
"\n"
|
||||||
|
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||||
|
" notice, this list of conditions and the following disclaimer in the\n"
|
||||||
|
" documentation and/or other materials provided with the distribution.\n"
|
||||||
|
"\n"
|
||||||
|
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
|
||||||
|
" names of its contributors may be used to endorse or promote products\n"
|
||||||
|
" derived from this software without specific prior written permission.\n"
|
||||||
|
"\n"
|
||||||
|
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
|
||||||
|
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
|
||||||
|
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
|
||||||
|
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
|
||||||
|
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
|
||||||
|
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
|
||||||
|
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
|
||||||
|
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
|
||||||
|
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
|
||||||
|
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
|
||||||
|
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||||
|
"\n";
|
||||||
|
|
||||||
|
static const char *commands_help =
|
||||||
|
"Commands:\n"
|
||||||
|
" mib get MIB variables (dot1x, dot11, radius)\n"
|
||||||
|
" sta <addr> get MIB variables for one station\n"
|
||||||
|
" all_sta get MIB variables for all stations\n"
|
||||||
|
" new_sta <addr> add a new station\n"
|
||||||
|
" help show this usage help\n"
|
||||||
|
" interface [ifname] show interfaces/select interface\n"
|
||||||
|
" level <debug level> change debug level\n"
|
||||||
|
" license show full hostapd_cli license\n"
|
||||||
|
" quit exit hostapd_cli\n";
|
||||||
|
|
||||||
|
static struct wpa_ctrl *ctrl_conn;
|
||||||
|
static int hostapd_cli_quit = 0;
|
||||||
|
static int hostapd_cli_attached = 0;
|
||||||
|
static const char *ctrl_iface_dir = "/var/run/hostapd";
|
||||||
|
static char *ctrl_ifname = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", hostapd_cli_version);
|
||||||
|
fprintf(stderr,
|
||||||
|
"\n"
|
||||||
|
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hv] "
|
||||||
|
"[command..]\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -h help (show this usage text)\n"
|
||||||
|
" -v shown version information\n"
|
||||||
|
" -p<path> path to find control sockets (default: "
|
||||||
|
"/var/run/hostapd)\n"
|
||||||
|
" -i<ifname> Interface to listen on (default: first "
|
||||||
|
"interface found in the\n"
|
||||||
|
" socket path)\n\n"
|
||||||
|
"%s",
|
||||||
|
commands_help);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||||
|
{
|
||||||
|
char *cfile;
|
||||||
|
int flen;
|
||||||
|
|
||||||
|
if (ifname == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
|
||||||
|
cfile = malloc(flen);
|
||||||
|
if (cfile == NULL)
|
||||||
|
return NULL;
|
||||||
|
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
|
||||||
|
|
||||||
|
ctrl_conn = wpa_ctrl_open(cfile);
|
||||||
|
free(cfile);
|
||||||
|
return ctrl_conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_cli_close_connection(void)
|
||||||
|
{
|
||||||
|
if (ctrl_conn == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hostapd_cli_attached) {
|
||||||
|
wpa_ctrl_detach(ctrl_conn);
|
||||||
|
hostapd_cli_attached = 0;
|
||||||
|
}
|
||||||
|
wpa_ctrl_close(ctrl_conn);
|
||||||
|
ctrl_conn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_cli_msg_cb(char *msg, size_t len)
|
||||||
|
{
|
||||||
|
printf("%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
size_t len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (ctrl_conn == NULL) {
|
||||||
|
printf("Not connected to hostapd - command dropped.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
len = sizeof(buf) - 1;
|
||||||
|
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||||
|
hostapd_cli_msg_cb);
|
||||||
|
if (ret == -2) {
|
||||||
|
printf("'%s' command timed out.\n", cmd);
|
||||||
|
return -2;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
printf("'%s' command failed.\n", cmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (print) {
|
||||||
|
buf[len] = '\0';
|
||||||
|
printf("%s", buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||||
|
{
|
||||||
|
return _wpa_ctrl_command(ctrl, cmd, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_ctrl_command(ctrl, "PING");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return wpa_ctrl_command(ctrl, "MIB");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
if (argc != 1) {
|
||||||
|
printf("Invalid 'sta' command - exactly one argument, STA "
|
||||||
|
"address, is required.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snprintf(buf, sizeof(buf), "STA %s", argv[0]);
|
||||||
|
return wpa_ctrl_command(ctrl, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
if (argc != 1) {
|
||||||
|
printf("Invalid 'new_sta' command - exactly one argument, STA "
|
||||||
|
"address, is required.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
|
||||||
|
return wpa_ctrl_command(ctrl, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||||
|
char *addr, size_t addr_len)
|
||||||
|
{
|
||||||
|
char buf[4096], *pos;
|
||||||
|
size_t len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (ctrl_conn == NULL) {
|
||||||
|
printf("Not connected to hostapd - command dropped.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
len = sizeof(buf) - 1;
|
||||||
|
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
|
||||||
|
hostapd_cli_msg_cb);
|
||||||
|
if (ret == -2) {
|
||||||
|
printf("'%s' command timed out.\n", cmd);
|
||||||
|
return -2;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
printf("'%s' command failed.\n", cmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (memcmp(buf, "FAIL", 4) == 0)
|
||||||
|
return -1;
|
||||||
|
printf("%s", buf);
|
||||||
|
|
||||||
|
pos = buf;
|
||||||
|
while (*pos != '\0' && *pos != '\n')
|
||||||
|
pos++;
|
||||||
|
*pos = '\0';
|
||||||
|
os_strlcpy(addr, buf, addr_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
char addr[32], cmd[64];
|
||||||
|
|
||||||
|
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||||
|
return 0;
|
||||||
|
do {
|
||||||
|
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||||
|
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
printf("%s", commands_help);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
hostapd_cli_quit = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char cmd[256];
|
||||||
|
if (argc != 1) {
|
||||||
|
printf("Invalid LEVEL command: needs one argument (debug "
|
||||||
|
"level)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
|
||||||
|
return wpa_ctrl_command(ctrl, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
struct dirent *dent;
|
||||||
|
DIR *dir;
|
||||||
|
|
||||||
|
dir = opendir(ctrl_iface_dir);
|
||||||
|
if (dir == NULL) {
|
||||||
|
printf("Control interface directory '%s' could not be "
|
||||||
|
"openned.\n", ctrl_iface_dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Available interfaces:\n");
|
||||||
|
while ((dent = readdir(dir))) {
|
||||||
|
if (strcmp(dent->d_name, ".") == 0 ||
|
||||||
|
strcmp(dent->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
printf("%s\n", dent->d_name);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 1) {
|
||||||
|
hostapd_cli_list_interfaces(ctrl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostapd_cli_close_connection();
|
||||||
|
free(ctrl_ifname);
|
||||||
|
ctrl_ifname = strdup(argv[0]);
|
||||||
|
|
||||||
|
if (hostapd_cli_open_connection(ctrl_ifname)) {
|
||||||
|
printf("Connected to interface '%s.\n", ctrl_ifname);
|
||||||
|
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||||
|
hostapd_cli_attached = 1;
|
||||||
|
} else {
|
||||||
|
printf("Warning: Failed to attach to "
|
||||||
|
"hostapd.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Could not connect to interface '%s' - re-trying\n",
|
||||||
|
ctrl_ifname);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_cli_cmd {
|
||||||
|
const char *cmd;
|
||||||
|
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||||
|
{ "ping", hostapd_cli_cmd_ping },
|
||||||
|
{ "mib", hostapd_cli_cmd_mib },
|
||||||
|
{ "sta", hostapd_cli_cmd_sta },
|
||||||
|
{ "all_sta", hostapd_cli_cmd_all_sta },
|
||||||
|
{ "new_sta", hostapd_cli_cmd_new_sta },
|
||||||
|
{ "help", hostapd_cli_cmd_help },
|
||||||
|
{ "interface", hostapd_cli_cmd_interface },
|
||||||
|
{ "level", hostapd_cli_cmd_level },
|
||||||
|
{ "license", hostapd_cli_cmd_license },
|
||||||
|
{ "quit", hostapd_cli_cmd_quit },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
cmd = hostapd_cli_commands;
|
||||||
|
while (cmd->cmd) {
|
||||||
|
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
|
||||||
|
match = cmd;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
cmd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1) {
|
||||||
|
printf("Ambiguous command '%s'; possible commands:", argv[0]);
|
||||||
|
cmd = hostapd_cli_commands;
|
||||||
|
while (cmd->cmd) {
|
||||||
|
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
|
||||||
|
0) {
|
||||||
|
printf(" %s", cmd->cmd);
|
||||||
|
}
|
||||||
|
cmd++;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
} else if (count == 0) {
|
||||||
|
printf("Unknown command '%s'\n", argv[0]);
|
||||||
|
} else {
|
||||||
|
match->handler(ctrl, argc - 1, &argv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
|
||||||
|
{
|
||||||
|
int first = 1;
|
||||||
|
if (ctrl_conn == NULL)
|
||||||
|
return;
|
||||||
|
while (wpa_ctrl_pending(ctrl)) {
|
||||||
|
char buf[256];
|
||||||
|
size_t len = sizeof(buf) - 1;
|
||||||
|
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (in_read && first)
|
||||||
|
printf("\n");
|
||||||
|
first = 0;
|
||||||
|
printf("%s\n", buf);
|
||||||
|
} else {
|
||||||
|
printf("Could not read pending message.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_cli_interactive(void)
|
||||||
|
{
|
||||||
|
const int max_args = 10;
|
||||||
|
char cmd[256], *res, *argv[max_args], *pos;
|
||||||
|
int argc;
|
||||||
|
|
||||||
|
printf("\nInteractive mode\n\n");
|
||||||
|
|
||||||
|
do {
|
||||||
|
hostapd_cli_recv_pending(ctrl_conn, 0);
|
||||||
|
printf("> ");
|
||||||
|
alarm(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 && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
|
||||||
|
printf("Connection to hostapd lost - trying to reconnect\n");
|
||||||
|
hostapd_cli_close_connection();
|
||||||
|
}
|
||||||
|
if (!ctrl_conn) {
|
||||||
|
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||||
|
if (ctrl_conn) {
|
||||||
|
printf("Connection to hostapd re-established\n");
|
||||||
|
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||||
|
hostapd_cli_attached = 1;
|
||||||
|
} else {
|
||||||
|
printf("Warning: Failed to attach to "
|
||||||
|
"hostapd.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ctrl_conn)
|
||||||
|
hostapd_cli_recv_pending(ctrl_conn, 1);
|
||||||
|
alarm(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':
|
||||||
|
free(ctrl_ifname);
|
||||||
|
ctrl_ifname = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
ctrl_iface_dir = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interactive = argc == optind;
|
||||||
|
|
||||||
|
if (interactive) {
|
||||||
|
printf("%s\n\n%s\n\n", hostapd_cli_version,
|
||||||
|
hostapd_cli_license);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (ctrl_ifname == NULL) {
|
||||||
|
struct dirent *dent;
|
||||||
|
DIR *dir = opendir(ctrl_iface_dir);
|
||||||
|
if (dir) {
|
||||||
|
while ((dent = readdir(dir))) {
|
||||||
|
if (strcmp(dent->d_name, ".") == 0 ||
|
||||||
|
strcmp(dent->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
printf("Selected interface '%s'\n",
|
||||||
|
dent->d_name);
|
||||||
|
ctrl_ifname = strdup(dent->d_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||||
|
if (ctrl_conn) {
|
||||||
|
if (warning_displayed)
|
||||||
|
printf("Connection established.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!interactive) {
|
||||||
|
perror("Failed to connect to hostapd - "
|
||||||
|
"wpa_ctrl_open");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!warning_displayed) {
|
||||||
|
printf("Could not connect to hostapd - re-trying\n");
|
||||||
|
warning_displayed = 1;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGINT, hostapd_cli_terminate);
|
||||||
|
signal(SIGTERM, hostapd_cli_terminate);
|
||||||
|
signal(SIGALRM, hostapd_cli_alarm);
|
||||||
|
|
||||||
|
if (interactive) {
|
||||||
|
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||||
|
hostapd_cli_attached = 1;
|
||||||
|
} else {
|
||||||
|
printf("Warning: Failed to attach to hostapd.\n");
|
||||||
|
}
|
||||||
|
hostapd_cli_interactive();
|
||||||
|
} else
|
||||||
|
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
|
||||||
|
|
||||||
|
free(ctrl_ifname);
|
||||||
|
hostapd_cli_close_connection();
|
||||||
|
return 0;
|
||||||
|
}
|
432
hostapd/hw_features.c
Normal file
432
hostapd/hw_features.c
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Hardware feature query and different modes
|
||||||
|
* Copyright 2002-2003, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||||
|
size_t num_hw_features)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (hw_features == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < num_hw_features; i++) {
|
||||||
|
os_free(hw_features[i].channels);
|
||||||
|
os_free(hw_features[i].rates);
|
||||||
|
}
|
||||||
|
|
||||||
|
os_free(hw_features);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
|
int ret = 0, i, j;
|
||||||
|
u16 num_modes, flags;
|
||||||
|
struct hostapd_hw_modes *modes;
|
||||||
|
|
||||||
|
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
|
||||||
|
if (modes == NULL) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"Fetching hardware channel/rate support not "
|
||||||
|
"supported.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface->hw_flags = flags;
|
||||||
|
|
||||||
|
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||||
|
iface->hw_features = modes;
|
||||||
|
iface->num_hw_features = num_modes;
|
||||||
|
|
||||||
|
for (i = 0; i < num_modes; i++) {
|
||||||
|
struct hostapd_hw_modes *feature = &modes[i];
|
||||||
|
/* set flag for channels we can use in current regulatory
|
||||||
|
* domain */
|
||||||
|
for (j = 0; j < feature->num_channels; j++) {
|
||||||
|
/* TODO: add regulatory domain lookup */
|
||||||
|
unsigned char power_level = 0;
|
||||||
|
unsigned char antenna_max = 0;
|
||||||
|
|
||||||
|
if ((feature->mode == HOSTAPD_MODE_IEEE80211G ||
|
||||||
|
feature->mode == HOSTAPD_MODE_IEEE80211B) &&
|
||||||
|
feature->channels[j].chan >= 1 &&
|
||||||
|
feature->channels[j].chan <= 11) {
|
||||||
|
power_level = 20;
|
||||||
|
feature->channels[j].flag |=
|
||||||
|
HOSTAPD_CHAN_W_SCAN;
|
||||||
|
} else
|
||||||
|
feature->channels[j].flag &=
|
||||||
|
~HOSTAPD_CHAN_W_SCAN;
|
||||||
|
|
||||||
|
hostapd_set_channel_flag(hapd, feature->mode,
|
||||||
|
feature->channels[j].chan,
|
||||||
|
feature->channels[j].flag,
|
||||||
|
power_level,
|
||||||
|
antenna_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_prepare_rates(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_hw_modes *mode)
|
||||||
|
{
|
||||||
|
int i, num_basic_rates = 0;
|
||||||
|
int basic_rates_a[] = { 60, 120, 240, -1 };
|
||||||
|
int basic_rates_b[] = { 10, 20, -1 };
|
||||||
|
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
|
||||||
|
int *basic_rates;
|
||||||
|
|
||||||
|
if (hapd->iconf->basic_rates)
|
||||||
|
basic_rates = hapd->iconf->basic_rates;
|
||||||
|
else switch (mode->mode) {
|
||||||
|
case HOSTAPD_MODE_IEEE80211A:
|
||||||
|
basic_rates = basic_rates_a;
|
||||||
|
break;
|
||||||
|
case HOSTAPD_MODE_IEEE80211B:
|
||||||
|
basic_rates = basic_rates_b;
|
||||||
|
break;
|
||||||
|
case HOSTAPD_MODE_IEEE80211G:
|
||||||
|
basic_rates = basic_rates_g;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
|
||||||
|
basic_rates, mode->mode)) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
|
||||||
|
"module");
|
||||||
|
}
|
||||||
|
|
||||||
|
os_free(hapd->iface->current_rates);
|
||||||
|
hapd->iface->num_rates = 0;
|
||||||
|
|
||||||
|
hapd->iface->current_rates =
|
||||||
|
os_malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
|
||||||
|
if (!hapd->iface->current_rates) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
|
||||||
|
"table.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < mode->num_rates; i++) {
|
||||||
|
struct hostapd_rate_data *rate;
|
||||||
|
|
||||||
|
if (hapd->iconf->supported_rates &&
|
||||||
|
!hostapd_rate_found(hapd->iconf->supported_rates,
|
||||||
|
mode->rates[i].rate))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
|
||||||
|
os_memcpy(rate, &mode->rates[i],
|
||||||
|
sizeof(struct hostapd_rate_data));
|
||||||
|
if (hostapd_rate_found(basic_rates, rate->rate)) {
|
||||||
|
rate->flags |= HOSTAPD_RATE_BASIC;
|
||||||
|
num_basic_rates++;
|
||||||
|
} else
|
||||||
|
rate->flags &= ~HOSTAPD_RATE_BASIC;
|
||||||
|
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
|
||||||
|
hapd->iface->num_rates, rate->rate, rate->flags);
|
||||||
|
hapd->iface->num_rates++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
|
||||||
|
wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
|
||||||
|
"rate sets (%d,%d).",
|
||||||
|
hapd->iface->num_rates, num_basic_rates);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void select_hw_mode_start(void *eloop_data, void *user_ctx);
|
||||||
|
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select_hw_mode_finalize - Finish select HW mode & call the callback
|
||||||
|
* @iface: Pointer to interface data.
|
||||||
|
* @status: Status of the select HW mode (0 on success; -1 on failure).
|
||||||
|
* Returns: 0 on success; -1 on failure (e.g., was not in progress).
|
||||||
|
*/
|
||||||
|
static int select_hw_mode_finalize(struct hostapd_iface *iface, int status)
|
||||||
|
{
|
||||||
|
hostapd_iface_cb cb;
|
||||||
|
|
||||||
|
if (!iface->hw_mode_sel_cb)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(select_hw_mode_start, iface, NULL);
|
||||||
|
eloop_cancel_timeout(select_hw_mode2_handler, iface, NULL);
|
||||||
|
|
||||||
|
cb = iface->hw_mode_sel_cb;
|
||||||
|
|
||||||
|
iface->hw_mode_sel_cb = NULL;
|
||||||
|
|
||||||
|
cb(iface, status);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select_hw_mode2 - Select the hardware mode (part 2)
|
||||||
|
* @iface: Pointer to interface data.
|
||||||
|
* @status: Status of auto chanel selection.
|
||||||
|
*
|
||||||
|
* Setup the rates and passive scanning based on the configuration.
|
||||||
|
*/
|
||||||
|
static void select_hw_mode2(struct hostapd_iface *iface, int status)
|
||||||
|
{
|
||||||
|
int ret = status;
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (iface->current_mode == NULL) {
|
||||||
|
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"Hardware does not support configured channel");
|
||||||
|
ret = -1;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
|
||||||
|
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"Failed to prepare rates table.");
|
||||||
|
ret = -1;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hostapd_passive_scan(iface->bss[0], 0,
|
||||||
|
iface->conf->passive_scan_mode,
|
||||||
|
iface->conf->passive_scan_interval,
|
||||||
|
iface->conf->passive_scan_listen,
|
||||||
|
NULL, NULL);
|
||||||
|
if (ret) {
|
||||||
|
wpa_printf(MSG_ERROR, "Could not set passive scanning: %s",
|
||||||
|
strerror(ret));
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
select_hw_mode_finalize(iface, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
|
||||||
|
* @eloop_data: Stores the struct hostapd_iface * for the interface.
|
||||||
|
* @user_ctx: Unused.
|
||||||
|
*/
|
||||||
|
static void select_hw_mode2_handler(void *eloop_data, void *user_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *iface = eloop_data;
|
||||||
|
|
||||||
|
select_hw_mode2(iface, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select_hw_mode1 - Select the hardware mode (part 1)
|
||||||
|
* @iface: Pointer to interface data.
|
||||||
|
* Returns: 0 on success; -1 on failure.
|
||||||
|
*
|
||||||
|
* Setup the hardware mode and channel based on the configuration.
|
||||||
|
* Schedules select_hw_mode2() to be called immediately or after automatic
|
||||||
|
* channel selection takes place.
|
||||||
|
*/
|
||||||
|
static int select_hw_mode1(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
int i, j, ok;
|
||||||
|
|
||||||
|
if (iface->num_hw_features < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
iface->current_mode = NULL;
|
||||||
|
for (i = 0; i < iface->num_hw_features; i++) {
|
||||||
|
struct hostapd_hw_modes *mode = &iface->hw_features[i];
|
||||||
|
if (mode->mode == (int) iface->conf->hw_mode) {
|
||||||
|
iface->current_mode = mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iface->current_mode == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "Hardware does not support configured "
|
||||||
|
"mode");
|
||||||
|
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"Hardware does not support configured mode "
|
||||||
|
"(%d)", (int) iface->conf->hw_mode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
for (j = 0; j < iface->current_mode->num_channels; j++) {
|
||||||
|
struct hostapd_channel_data *chan =
|
||||||
|
&iface->current_mode->channels[j];
|
||||||
|
if ((chan->flag & HOSTAPD_CHAN_W_SCAN) &&
|
||||||
|
(chan->chan == iface->conf->channel)) {
|
||||||
|
ok = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok == 0 && iface->conf->channel != 0) {
|
||||||
|
hostapd_logger(iface->bss[0], NULL,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"Configured channel (%d) not found from the "
|
||||||
|
"channel list of current mode (%d) %s",
|
||||||
|
iface->conf->channel,
|
||||||
|
iface->current_mode->mode,
|
||||||
|
hostapd_hw_mode_txt(iface->current_mode->mode));
|
||||||
|
iface->current_mode = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calls select_hw_mode2() via a handler, so that the function is
|
||||||
|
* always executed from eloop.
|
||||||
|
*/
|
||||||
|
eloop_register_timeout(0, 0, select_hw_mode2_handler, iface, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select_hw_mode_start - Handler to start select HW mode
|
||||||
|
* @eloop_data: Stores the struct hostapd_iface * for the interface.
|
||||||
|
* @user_ctx: Unused.
|
||||||
|
*
|
||||||
|
* An eloop handler is used so that all errors can be processed by the
|
||||||
|
* callback without introducing stack recursion.
|
||||||
|
*/
|
||||||
|
static void select_hw_mode_start(void *eloop_data, void *user_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *iface = (struct hostapd_iface *)eloop_data;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = select_hw_mode1(iface);
|
||||||
|
if (ret)
|
||||||
|
select_hw_mode_finalize(iface, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_select_hw_mode_start - Start selection of the hardware mode
|
||||||
|
* @iface: Pointer to interface data.
|
||||||
|
* @cb: The function to callback when done.
|
||||||
|
* Returns: 0 if it starts successfully; cb will be called when done.
|
||||||
|
* -1 on failure; cb will not be called.
|
||||||
|
*
|
||||||
|
* Sets up the hardware mode, channel, rates, and passive scanning
|
||||||
|
* based on the configuration.
|
||||||
|
*/
|
||||||
|
int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
|
||||||
|
hostapd_iface_cb cb)
|
||||||
|
{
|
||||||
|
if (iface->hw_mode_sel_cb) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"%s: Hardware mode select already in progress.",
|
||||||
|
iface->bss[0]->conf->iface);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface->hw_mode_sel_cb = cb;
|
||||||
|
|
||||||
|
eloop_register_timeout(0, 0, select_hw_mode_start, iface, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_auto_chan_select_stop - Stops automatic channel selection
|
||||||
|
* @iface: Pointer to interface data.
|
||||||
|
* Returns: 0 if successfully stopped;
|
||||||
|
* -1 on failure (i.e., was not in progress)
|
||||||
|
*/
|
||||||
|
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
return select_hw_mode_finalize(iface, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char * hostapd_hw_mode_txt(int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case HOSTAPD_MODE_IEEE80211A:
|
||||||
|
return "IEEE 802.11a";
|
||||||
|
case HOSTAPD_MODE_IEEE80211B:
|
||||||
|
return "IEEE 802.11b";
|
||||||
|
case HOSTAPD_MODE_IEEE80211G:
|
||||||
|
return "IEEE 802.11g";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!hapd->iface->current_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||||
|
struct hostapd_channel_data *ch =
|
||||||
|
&hapd->iface->current_mode->channels[i];
|
||||||
|
if (ch->chan == chan)
|
||||||
|
return ch->freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!hapd->iface->current_mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
|
||||||
|
struct hostapd_channel_data *ch =
|
||||||
|
&hapd->iface->current_mode->channels[i];
|
||||||
|
if (ch->freq == freq)
|
||||||
|
return ch->chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
61
hostapd/hw_features.h
Normal file
61
hostapd/hw_features.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Hardware feature query and different modes
|
||||||
|
* Copyright 2002-2003, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_FEATURES_H
|
||||||
|
#define HW_FEATURES_H
|
||||||
|
|
||||||
|
#define HOSTAPD_CHAN_W_SCAN 0x00000001
|
||||||
|
#define HOSTAPD_CHAN_W_ACTIVE_SCAN 0x00000002
|
||||||
|
#define HOSTAPD_CHAN_W_IBSS 0x00000004
|
||||||
|
|
||||||
|
struct hostapd_channel_data {
|
||||||
|
short chan; /* channel number (IEEE 802.11) */
|
||||||
|
short freq; /* frequency in MHz */
|
||||||
|
int flag; /* flag for hostapd use (HOSTAPD_CHAN_*) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HOSTAPD_RATE_ERP 0x00000001
|
||||||
|
#define HOSTAPD_RATE_BASIC 0x00000002
|
||||||
|
#define HOSTAPD_RATE_PREAMBLE2 0x00000004
|
||||||
|
#define HOSTAPD_RATE_SUPPORTED 0x00000010
|
||||||
|
#define HOSTAPD_RATE_OFDM 0x00000020
|
||||||
|
#define HOSTAPD_RATE_CCK 0x00000040
|
||||||
|
#define HOSTAPD_RATE_MANDATORY 0x00000100
|
||||||
|
|
||||||
|
struct hostapd_rate_data {
|
||||||
|
int rate; /* rate in 100 kbps */
|
||||||
|
int flags; /* HOSTAPD_RATE_ flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hostapd_hw_modes {
|
||||||
|
int mode;
|
||||||
|
int num_channels;
|
||||||
|
struct hostapd_channel_data *channels;
|
||||||
|
int num_rates;
|
||||||
|
struct hostapd_rate_data *rates;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||||
|
size_t num_hw_features);
|
||||||
|
int hostapd_get_hw_features(struct hostapd_iface *iface);
|
||||||
|
int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
|
||||||
|
hostapd_iface_cb cb);
|
||||||
|
int hostapd_select_hw_mode_stop(struct hostapd_iface *iface);
|
||||||
|
const char * hostapd_hw_mode_txt(int mode);
|
||||||
|
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
|
||||||
|
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
|
||||||
|
|
||||||
|
#endif /* HW_FEATURES_H */
|
542
hostapd/iapp.c
Normal file
542
hostapd/iapp.c
Normal file
|
@ -0,0 +1,542 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*
|
||||||
|
* Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
|
||||||
|
* and IEEE has withdrawn it. In other words, it is likely better to look at
|
||||||
|
* using some other mechanism for AP-to-AP communication than extenting the
|
||||||
|
* implementation here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* Level 1: no administrative or security support
|
||||||
|
* (e.g., static BSSID to IP address mapping in each AP)
|
||||||
|
* Level 2: support for dynamic mapping of BSSID to IP address
|
||||||
|
* Level 3: support for encryption and authentication of IAPP messages
|
||||||
|
* - add support for MOVE-notify and MOVE-response (this requires support for
|
||||||
|
* finding out IP address for previous AP using RADIUS)
|
||||||
|
* - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
|
||||||
|
* reassociation to another AP
|
||||||
|
* - implement counters etc. for IAPP MIB
|
||||||
|
* - verify endianness of fields in IAPP messages; are they big-endian as
|
||||||
|
* used here?
|
||||||
|
* - RADIUS connection for AP registration and BSSID to IP address mapping
|
||||||
|
* - TCP connection for IAPP MOVE, CACHE
|
||||||
|
* - broadcast ESP for IAPP ADD-notify
|
||||||
|
* - ESP for IAPP MOVE messages
|
||||||
|
* - security block sending/processing
|
||||||
|
* - IEEE 802.11 context transfer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef USE_KERNEL_HEADERS
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#else /* USE_KERNEL_HEADERS */
|
||||||
|
#include <netpacket/packet.h>
|
||||||
|
#endif /* USE_KERNEL_HEADERS */
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "iapp.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define IAPP_MULTICAST "224.0.1.178"
|
||||||
|
#define IAPP_UDP_PORT 3517
|
||||||
|
#define IAPP_TCP_PORT 3517
|
||||||
|
|
||||||
|
struct iapp_hdr {
|
||||||
|
u8 version;
|
||||||
|
u8 command;
|
||||||
|
be16 identifier;
|
||||||
|
be16 length;
|
||||||
|
/* followed by length-6 octets of data */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define IAPP_VERSION 0
|
||||||
|
|
||||||
|
enum IAPP_COMMAND {
|
||||||
|
IAPP_CMD_ADD_notify = 0,
|
||||||
|
IAPP_CMD_MOVE_notify = 1,
|
||||||
|
IAPP_CMD_MOVE_response = 2,
|
||||||
|
IAPP_CMD_Send_Security_Block = 3,
|
||||||
|
IAPP_CMD_ACK_Security_Block = 4,
|
||||||
|
IAPP_CMD_CACHE_notify = 5,
|
||||||
|
IAPP_CMD_CACHE_response = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ADD-notify - multicast UDP on the local LAN */
|
||||||
|
struct iapp_add_notify {
|
||||||
|
u8 addr_len; /* ETH_ALEN */
|
||||||
|
u8 reserved;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
be16 seq_num;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
|
||||||
|
struct iapp_layer2_update {
|
||||||
|
u8 da[ETH_ALEN]; /* broadcast */
|
||||||
|
u8 sa[ETH_ALEN]; /* STA addr */
|
||||||
|
be16 len; /* 6 */
|
||||||
|
u8 dsap; /* null DSAP address */
|
||||||
|
u8 ssap; /* null SSAP address, CR=Response */
|
||||||
|
u8 control;
|
||||||
|
u8 xid_info[3];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* MOVE-notify - unicast TCP */
|
||||||
|
struct iapp_move_notify {
|
||||||
|
u8 addr_len; /* ETH_ALEN */
|
||||||
|
u8 reserved;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
u16 seq_num;
|
||||||
|
u16 ctx_block_len;
|
||||||
|
/* followed by ctx_block_len bytes */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* MOVE-response - unicast TCP */
|
||||||
|
struct iapp_move_response {
|
||||||
|
u8 addr_len; /* ETH_ALEN */
|
||||||
|
u8 status;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
u16 seq_num;
|
||||||
|
u16 ctx_block_len;
|
||||||
|
/* followed by ctx_block_len bytes */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IAPP_MOVE_SUCCESSFUL = 0,
|
||||||
|
IAPP_MOVE_DENIED = 1,
|
||||||
|
IAPP_MOVE_STALE_MOVE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* CACHE-notify */
|
||||||
|
struct iapp_cache_notify {
|
||||||
|
u8 addr_len; /* ETH_ALEN */
|
||||||
|
u8 reserved;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
u16 seq_num;
|
||||||
|
u8 current_ap[ETH_ALEN];
|
||||||
|
u16 ctx_block_len;
|
||||||
|
/* ctx_block_len bytes of context block followed by 16-bit context
|
||||||
|
* timeout */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* CACHE-response - unicast TCP */
|
||||||
|
struct iapp_cache_response {
|
||||||
|
u8 addr_len; /* ETH_ALEN */
|
||||||
|
u8 status;
|
||||||
|
u8 mac_addr[ETH_ALEN];
|
||||||
|
u16 seq_num;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IAPP_CACHE_SUCCESSFUL = 0,
|
||||||
|
IAPP_CACHE_STALE_CACHE = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Send-Security-Block - unicast TCP */
|
||||||
|
struct iapp_send_security_block {
|
||||||
|
u8 iv[8];
|
||||||
|
u16 sec_block_len;
|
||||||
|
/* followed by sec_block_len bytes of security block */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/* ACK-Security-Block - unicast TCP */
|
||||||
|
struct iapp_ack_security_block {
|
||||||
|
u8 iv[8];
|
||||||
|
u8 new_ap_ack_authenticator[48];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
struct iapp_data {
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
u16 identifier; /* next IAPP identifier */
|
||||||
|
struct in_addr own, multicast;
|
||||||
|
int udp_sock;
|
||||||
|
int packet_sock;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
struct iapp_hdr *hdr;
|
||||||
|
struct iapp_add_notify *add;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
/* Send IAPP ADD-notify to remove possible association from other APs
|
||||||
|
*/
|
||||||
|
|
||||||
|
hdr = (struct iapp_hdr *) buf;
|
||||||
|
hdr->version = IAPP_VERSION;
|
||||||
|
hdr->command = IAPP_CMD_ADD_notify;
|
||||||
|
hdr->identifier = host_to_be16(iapp->identifier++);
|
||||||
|
hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
|
||||||
|
|
||||||
|
add = (struct iapp_add_notify *) (hdr + 1);
|
||||||
|
add->addr_len = ETH_ALEN;
|
||||||
|
add->reserved = 0;
|
||||||
|
os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
add->seq_num = host_to_be16(seq_num);
|
||||||
|
|
||||||
|
os_memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = iapp->multicast.s_addr;
|
||||||
|
addr.sin_port = htons(IAPP_UDP_PORT);
|
||||||
|
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
|
||||||
|
(struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||||
|
perror("sendto[IAPP-ADD]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
|
||||||
|
{
|
||||||
|
struct iapp_layer2_update msg;
|
||||||
|
|
||||||
|
/* Send Level 2 Update Frame to update forwarding tables in layer 2
|
||||||
|
* bridge devices */
|
||||||
|
|
||||||
|
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
|
||||||
|
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
|
||||||
|
|
||||||
|
os_memset(msg.da, 0xff, ETH_ALEN);
|
||||||
|
os_memcpy(msg.sa, addr, ETH_ALEN);
|
||||||
|
msg.len = host_to_be16(6);
|
||||||
|
msg.dsap = 0; /* NULL DSAP address */
|
||||||
|
msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
|
||||||
|
msg.control = 0xaf; /* XID response lsb.1111F101.
|
||||||
|
* F=0 (no poll command; unsolicited frame) */
|
||||||
|
msg.xid_info[0] = 0x81; /* XID format identifier */
|
||||||
|
msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
|
||||||
|
msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
|
||||||
|
* FIX: what is correct RW with 802.11? */
|
||||||
|
|
||||||
|
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
|
||||||
|
perror("send[L2 Update]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from.sin_addr.s_addr == iapp->own.s_addr)
|
||||||
|
return; /* ignore own IAPP messages */
|
||||||
|
|
||||||
|
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"Received %d byte IAPP frame from %s%s\n",
|
||||||
|
len, inet_ntoa(from.sin_addr),
|
||||||
|
len < (int) sizeof(*hdr) ? " (too short)" : "");
|
||||||
|
|
||||||
|
if (len < (int) sizeof(*hdr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
hdr = (struct iapp_hdr *) buf;
|
||||||
|
hlen = be_to_host16(hdr->length);
|
||||||
|
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"RX: version=%d command=%d id=%d len=%d\n",
|
||||||
|
hdr->version, hdr->command,
|
||||||
|
be_to_host16(hdr->identifier), hlen);
|
||||||
|
if (hdr->version != IAPP_VERSION) {
|
||||||
|
printf("Dropping IAPP frame with unknown version %d\n",
|
||||||
|
hdr->version);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hlen > len) {
|
||||||
|
printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hlen < len) {
|
||||||
|
printf("Ignoring %d extra bytes from IAPP frame\n",
|
||||||
|
len - hlen);
|
||||||
|
len = hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (hdr->command) {
|
||||||
|
case IAPP_CMD_ADD_notify:
|
||||||
|
iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
|
||||||
|
break;
|
||||||
|
case IAPP_CMD_MOVE_notify:
|
||||||
|
/* TODO: MOVE is using TCP; so move this to TCP handler once it
|
||||||
|
* is implemented.. */
|
||||||
|
/* IAPP-MOVE.indication(MAC Address, New BSSID,
|
||||||
|
* Sequence Number, AP Address, Context Block) */
|
||||||
|
/* TODO: process */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown IAPP command %d\n", hdr->command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct sockaddr_ll addr;
|
||||||
|
int ifindex;
|
||||||
|
struct sockaddr_in *paddr, uaddr;
|
||||||
|
struct iapp_data *iapp;
|
||||||
|
struct ip_mreqn mreq;
|
||||||
|
|
||||||
|
iapp = os_zalloc(sizeof(*iapp));
|
||||||
|
if (iapp == NULL)
|
||||||
|
return NULL;
|
||||||
|
iapp->hapd = hapd;
|
||||||
|
iapp->udp_sock = iapp->packet_sock = -1;
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* open socket for sending and receiving IAPP frames over TCP
|
||||||
|
*/
|
||||||
|
|
||||||
|
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (iapp->udp_sock < 0) {
|
||||||
|
perror("socket[PF_INET,SOCK_DGRAM]");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
|
||||||
|
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
|
||||||
|
perror("ioctl(SIOCGIFINDEX)");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ifindex = ifr.ifr_ifindex;
|
||||||
|
|
||||||
|
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
|
||||||
|
perror("ioctl(SIOCGIFADDR)");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
|
||||||
|
if (paddr->sin_family != AF_INET) {
|
||||||
|
printf("Invalid address family %i (SIOCGIFADDR)\n",
|
||||||
|
paddr->sin_family);
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
iapp->own.s_addr = paddr->sin_addr.s_addr;
|
||||||
|
|
||||||
|
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
|
||||||
|
perror("ioctl(SIOCGIFBRDADDR)");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
|
||||||
|
if (paddr->sin_family != AF_INET) {
|
||||||
|
printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
|
||||||
|
paddr->sin_family);
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
inet_aton(IAPP_MULTICAST, &iapp->multicast);
|
||||||
|
|
||||||
|
os_memset(&uaddr, 0, sizeof(uaddr));
|
||||||
|
uaddr.sin_family = AF_INET;
|
||||||
|
uaddr.sin_port = htons(IAPP_UDP_PORT);
|
||||||
|
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
|
||||||
|
sizeof(uaddr)) < 0) {
|
||||||
|
perror("bind[UDP]");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&mreq, 0, sizeof(mreq));
|
||||||
|
mreq.imr_multiaddr = iapp->multicast;
|
||||||
|
mreq.imr_address.s_addr = INADDR_ANY;
|
||||||
|
mreq.imr_ifindex = 0;
|
||||||
|
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
|
||||||
|
sizeof(mreq)) < 0) {
|
||||||
|
perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||||
|
if (iapp->packet_sock < 0) {
|
||||||
|
perror("socket[PF_PACKET,SOCK_RAW]");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sll_family = AF_PACKET;
|
||||||
|
addr.sll_ifindex = ifindex;
|
||||||
|
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
|
||||||
|
sizeof(addr)) < 0) {
|
||||||
|
perror("bind[PACKET]");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
|
||||||
|
iapp, NULL)) {
|
||||||
|
printf("Could not register read socket for IAPP.\n");
|
||||||
|
iapp_deinit(iapp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
|
||||||
|
|
||||||
|
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
|
||||||
|
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
|
||||||
|
* be openned only after receiving Initiate-Accept. If Initiate-Reject
|
||||||
|
* is received, IAPP is not started. */
|
||||||
|
|
||||||
|
return iapp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void iapp_deinit(struct iapp_data *iapp)
|
||||||
|
{
|
||||||
|
struct ip_mreqn mreq;
|
||||||
|
|
||||||
|
if (iapp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (iapp->udp_sock >= 0) {
|
||||||
|
os_memset(&mreq, 0, sizeof(mreq));
|
||||||
|
mreq.imr_multiaddr = iapp->multicast;
|
||||||
|
mreq.imr_address.s_addr = INADDR_ANY;
|
||||||
|
mreq.imr_ifindex = 0;
|
||||||
|
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
|
||||||
|
&mreq, sizeof(mreq)) < 0) {
|
||||||
|
perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
|
||||||
|
}
|
||||||
|
|
||||||
|
eloop_unregister_read_sock(iapp->udp_sock);
|
||||||
|
close(iapp->udp_sock);
|
||||||
|
}
|
||||||
|
if (iapp->packet_sock >= 0) {
|
||||||
|
eloop_unregister_read_sock(iapp->packet_sock);
|
||||||
|
close(iapp->packet_sock);
|
||||||
|
}
|
||||||
|
os_free(iapp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss)
|
||||||
|
{
|
||||||
|
if (hapd->conf->ieee802_11f != oldbss->ieee802_11f ||
|
||||||
|
os_strcmp(hapd->conf->iapp_iface, oldbss->iapp_iface) != 0) {
|
||||||
|
iapp_deinit(hapd->iapp);
|
||||||
|
hapd->iapp = NULL;
|
||||||
|
|
||||||
|
if (hapd->conf->ieee802_11f) {
|
||||||
|
hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface);
|
||||||
|
if (hapd->iapp == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
54
hostapd/iapp.h
Normal file
54
hostapd/iapp.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
|
||||||
|
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IAPP_H
|
||||||
|
#define IAPP_H
|
||||||
|
|
||||||
|
struct iapp_data;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IAPP
|
||||||
|
|
||||||
|
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
|
||||||
|
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
|
||||||
|
void iapp_deinit(struct iapp_data *iapp);
|
||||||
|
int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss);
|
||||||
|
|
||||||
|
#else /* CONFIG_IAPP */
|
||||||
|
|
||||||
|
static inline void iapp_new_station(struct iapp_data *iapp,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
|
||||||
|
const char *iface)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void iapp_deinit(struct iapp_data *iapp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_IAPP */
|
||||||
|
|
||||||
|
#endif /* IAPP_H */
|
1749
hostapd/ieee802_11.c
Normal file
1749
hostapd/ieee802_11.c
Normal file
File diff suppressed because it is too large
Load diff
95
hostapd/ieee802_11.h
Normal file
95
hostapd/ieee802_11.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 Management
|
||||||
|
* Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_11_H
|
||||||
|
#define IEEE802_11_H
|
||||||
|
|
||||||
|
#include "ieee802_11_defs.h"
|
||||||
|
|
||||||
|
/* Parsed Information Elements */
|
||||||
|
struct ieee802_11_elems {
|
||||||
|
u8 *ssid;
|
||||||
|
u8 ssid_len;
|
||||||
|
u8 *supp_rates;
|
||||||
|
u8 supp_rates_len;
|
||||||
|
u8 *fh_params;
|
||||||
|
u8 fh_params_len;
|
||||||
|
u8 *ds_params;
|
||||||
|
u8 ds_params_len;
|
||||||
|
u8 *cf_params;
|
||||||
|
u8 cf_params_len;
|
||||||
|
u8 *tim;
|
||||||
|
u8 tim_len;
|
||||||
|
u8 *ibss_params;
|
||||||
|
u8 ibss_params_len;
|
||||||
|
u8 *challenge;
|
||||||
|
u8 challenge_len;
|
||||||
|
u8 *erp_info;
|
||||||
|
u8 erp_info_len;
|
||||||
|
u8 *ext_supp_rates;
|
||||||
|
u8 ext_supp_rates_len;
|
||||||
|
u8 *wpa_ie;
|
||||||
|
u8 wpa_ie_len;
|
||||||
|
u8 *rsn_ie;
|
||||||
|
u8 rsn_ie_len;
|
||||||
|
u8 *wme;
|
||||||
|
u8 wme_len;
|
||||||
|
u8 *wme_tspec;
|
||||||
|
u8 wme_tspec_len;
|
||||||
|
u8 *power_cap;
|
||||||
|
u8 power_cap_len;
|
||||||
|
u8 *supp_channels;
|
||||||
|
u8 supp_channels_len;
|
||||||
|
u8 *mdie;
|
||||||
|
u8 mdie_len;
|
||||||
|
u8 *ftie;
|
||||||
|
u8 ftie_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_frame_info {
|
||||||
|
u32 phytype;
|
||||||
|
u32 channel;
|
||||||
|
u32 datarate;
|
||||||
|
u32 ssi_signal;
|
||||||
|
|
||||||
|
unsigned int passive_scan:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hostapd_data;
|
||||||
|
struct sta_info;
|
||||||
|
|
||||||
|
void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason);
|
||||||
|
void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len,
|
||||||
|
u16 stype, struct hostapd_frame_info *fi);
|
||||||
|
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
|
||||||
|
u16 stype, int ok);
|
||||||
|
ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
|
||||||
|
size_t len,
|
||||||
|
struct ieee802_11_elems *elems,
|
||||||
|
int show_errors);
|
||||||
|
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
|
||||||
|
void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
int local);
|
||||||
|
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
|
||||||
|
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
char *buf, size_t buflen);
|
||||||
|
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int probe);
|
||||||
|
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||||
|
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||||
|
|
||||||
|
#endif /* IEEE802_11_H */
|
471
hostapd/ieee802_11_auth.c
Normal file
471
hostapd/ieee802_11_auth.c
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 authentication (ACL)
|
||||||
|
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "ieee802_11_auth.h"
|
||||||
|
#include "radius/radius.h"
|
||||||
|
#include "radius/radius_client.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
|
||||||
|
#define RADIUS_ACL_TIMEOUT 30
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_cached_radius_acl {
|
||||||
|
time_t timestamp;
|
||||||
|
macaddr addr;
|
||||||
|
int accepted; /* HOSTAPD_ACL_* */
|
||||||
|
struct hostapd_cached_radius_acl *next;
|
||||||
|
u32 session_timeout;
|
||||||
|
u32 acct_interim_interval;
|
||||||
|
int vlan_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_acl_query_data {
|
||||||
|
time_t timestamp;
|
||||||
|
u8 radius_id;
|
||||||
|
macaddr addr;
|
||||||
|
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
|
||||||
|
size_t auth_msg_len;
|
||||||
|
struct hostapd_acl_query_data *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
|
||||||
|
{
|
||||||
|
struct hostapd_cached_radius_acl *prev;
|
||||||
|
|
||||||
|
while (acl_cache) {
|
||||||
|
prev = acl_cache;
|
||||||
|
acl_cache = acl_cache->next;
|
||||||
|
os_free(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
u32 *session_timeout,
|
||||||
|
u32 *acct_interim_interval, int *vlan_id)
|
||||||
|
{
|
||||||
|
struct hostapd_cached_radius_acl *entry;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
entry = hapd->acl_cache;
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
|
||||||
|
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
|
||||||
|
return -1; /* entry has expired */
|
||||||
|
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||||
|
*session_timeout = entry->session_timeout;
|
||||||
|
*acct_interim_interval = entry->acct_interim_interval;
|
||||||
|
if (vlan_id)
|
||||||
|
*vlan_id = entry->vlan_id;
|
||||||
|
return entry->accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
|
||||||
|
{
|
||||||
|
if (query == NULL)
|
||||||
|
return;
|
||||||
|
os_free(query->auth_msg);
|
||||||
|
os_free(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
struct hostapd_acl_query_data *query)
|
||||||
|
{
|
||||||
|
struct radius_msg *msg;
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
query->radius_id = radius_client_get_id(hapd->radius);
|
||||||
|
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
|
||||||
|
if (msg == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
radius_msg_make_authenticator(msg, addr, ETH_ALEN);
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
|
||||||
|
os_strlen(buf))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add User-Name");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_user_password(
|
||||||
|
msg, (u8 *) buf, os_strlen(buf),
|
||||||
|
hapd->conf->radius->auth_server->shared_secret,
|
||||||
|
hapd->conf->radius->auth_server->shared_secret_len)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add User-Password");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hapd->conf->own_ip_addr.af == AF_INET &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
|
||||||
|
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPV6
|
||||||
|
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
|
||||||
|
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IPV6 */
|
||||||
|
|
||||||
|
if (hapd->conf->nas_identifier &&
|
||||||
|
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
|
||||||
|
(u8 *) hapd->conf->nas_identifier,
|
||||||
|
os_strlen(hapd->conf->nas_identifier))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
|
||||||
|
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
|
||||||
|
MAC2STR(addr));
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
|
||||||
|
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
|
||||||
|
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
|
||||||
|
(u8 *) buf, os_strlen(buf))) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
radius_msg_free(msg);
|
||||||
|
os_free(msg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
const u8 *msg, size_t len, u32 *session_timeout,
|
||||||
|
u32 *acct_interim_interval, int *vlan_id)
|
||||||
|
{
|
||||||
|
*session_timeout = 0;
|
||||||
|
*acct_interim_interval = 0;
|
||||||
|
if (vlan_id)
|
||||||
|
*vlan_id = 0;
|
||||||
|
|
||||||
|
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
||||||
|
hapd->conf->num_accept_mac, addr))
|
||||||
|
return HOSTAPD_ACL_ACCEPT;
|
||||||
|
|
||||||
|
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
||||||
|
hapd->conf->num_deny_mac, addr))
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
|
||||||
|
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
|
||||||
|
return HOSTAPD_ACL_ACCEPT;
|
||||||
|
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
|
||||||
|
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
|
||||||
|
struct hostapd_acl_query_data *query;
|
||||||
|
|
||||||
|
/* Check whether ACL cache has an entry for this station */
|
||||||
|
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||||
|
acct_interim_interval,
|
||||||
|
vlan_id);
|
||||||
|
if (res == HOSTAPD_ACL_ACCEPT ||
|
||||||
|
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||||
|
return res;
|
||||||
|
if (res == HOSTAPD_ACL_REJECT)
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
|
||||||
|
query = hapd->acl_queries;
|
||||||
|
while (query) {
|
||||||
|
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
|
||||||
|
/* pending query in RADIUS retransmit queue;
|
||||||
|
* do not generate a new one */
|
||||||
|
return HOSTAPD_ACL_PENDING;
|
||||||
|
}
|
||||||
|
query = query->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hapd->conf->radius->auth_server)
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
|
||||||
|
/* No entry in the cache - query external RADIUS server */
|
||||||
|
query = os_zalloc(sizeof(*query));
|
||||||
|
if (query == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "malloc for query data failed");
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
}
|
||||||
|
time(&query->timestamp);
|
||||||
|
os_memcpy(query->addr, addr, ETH_ALEN);
|
||||||
|
if (hostapd_radius_acl_query(hapd, addr, query)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
|
||||||
|
"for ACL query.");
|
||||||
|
hostapd_acl_query_free(query);
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
query->auth_msg = os_malloc(len);
|
||||||
|
if (query->auth_msg == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||||
|
"auth frame.");
|
||||||
|
hostapd_acl_query_free(query);
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
}
|
||||||
|
os_memcpy(query->auth_msg, msg, len);
|
||||||
|
query->auth_msg_len = len;
|
||||||
|
query->next = hapd->acl_queries;
|
||||||
|
hapd->acl_queries = query;
|
||||||
|
|
||||||
|
/* Queued data will be processed in hostapd_acl_recv_radius()
|
||||||
|
* when RADIUS server replies to the sent Access-Request. */
|
||||||
|
return HOSTAPD_ACL_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HOSTAPD_ACL_REJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
|
||||||
|
{
|
||||||
|
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
|
||||||
|
|
||||||
|
prev = NULL;
|
||||||
|
entry = hapd->acl_cache;
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
|
||||||
|
" has expired.", MAC2STR(entry->addr));
|
||||||
|
if (prev)
|
||||||
|
prev->next = entry->next;
|
||||||
|
else
|
||||||
|
hapd->acl_cache = entry->next;
|
||||||
|
|
||||||
|
tmp = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
os_free(tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
|
||||||
|
{
|
||||||
|
struct hostapd_acl_query_data *prev, *entry, *tmp;
|
||||||
|
|
||||||
|
prev = NULL;
|
||||||
|
entry = hapd->acl_queries;
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
|
||||||
|
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
|
||||||
|
" has expired.", MAC2STR(entry->addr));
|
||||||
|
if (prev)
|
||||||
|
prev->next = entry->next;
|
||||||
|
else
|
||||||
|
hapd->acl_queries = entry->next;
|
||||||
|
|
||||||
|
tmp = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
hostapd_acl_query_free(tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
hostapd_acl_expire_cache(hapd, now);
|
||||||
|
hostapd_acl_expire_queries(hapd, now);
|
||||||
|
|
||||||
|
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return 0 if RADIUS message was a reply to ACL query (and was processed here)
|
||||||
|
* or -1 if not. */
|
||||||
|
static RadiusRxResult
|
||||||
|
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||||
|
u8 *shared_secret, size_t shared_secret_len,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = data;
|
||||||
|
struct hostapd_acl_query_data *query, *prev;
|
||||||
|
struct hostapd_cached_radius_acl *cache;
|
||||||
|
|
||||||
|
query = hapd->acl_queries;
|
||||||
|
prev = NULL;
|
||||||
|
while (query) {
|
||||||
|
if (query->radius_id == msg->hdr->identifier)
|
||||||
|
break;
|
||||||
|
prev = query;
|
||||||
|
query = query->next;
|
||||||
|
}
|
||||||
|
if (query == NULL)
|
||||||
|
return RADIUS_RX_UNKNOWN;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
|
||||||
|
"message (id=%d)", query->radius_id);
|
||||||
|
|
||||||
|
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
|
||||||
|
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
|
||||||
|
"correct authenticator - dropped\n");
|
||||||
|
return RADIUS_RX_INVALID_AUTHENTICATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
|
||||||
|
msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
|
||||||
|
"query", msg->hdr->code);
|
||||||
|
return RADIUS_RX_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert Accept/Reject info into ACL cache */
|
||||||
|
cache = os_zalloc(sizeof(*cache));
|
||||||
|
if (cache == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
time(&cache->timestamp);
|
||||||
|
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
|
||||||
|
if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
|
||||||
|
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
|
||||||
|
&cache->session_timeout) == 0)
|
||||||
|
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
|
||||||
|
else
|
||||||
|
cache->accepted = HOSTAPD_ACL_ACCEPT;
|
||||||
|
|
||||||
|
if (radius_msg_get_attr_int32(
|
||||||
|
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
|
||||||
|
&cache->acct_interim_interval) == 0 &&
|
||||||
|
cache->acct_interim_interval < 60) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Ignored too small "
|
||||||
|
"Acct-Interim-Interval %d for STA " MACSTR,
|
||||||
|
cache->acct_interim_interval,
|
||||||
|
MAC2STR(query->addr));
|
||||||
|
cache->acct_interim_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->vlan_id = radius_msg_get_vlanid(msg);
|
||||||
|
} else
|
||||||
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||||
|
cache->next = hapd->acl_cache;
|
||||||
|
hapd->acl_cache = cache;
|
||||||
|
|
||||||
|
/* Re-send original authentication frame for 802.11 processing */
|
||||||
|
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
|
||||||
|
"successful RADIUS ACL query");
|
||||||
|
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
|
||||||
|
WLAN_FC_STYPE_AUTH, NULL);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (prev == NULL)
|
||||||
|
hapd->acl_queries = query->next;
|
||||||
|
else
|
||||||
|
prev->next = query->next;
|
||||||
|
|
||||||
|
hostapd_acl_query_free(query);
|
||||||
|
|
||||||
|
return RADIUS_RX_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_acl_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (radius_client_register(hapd->radius, RADIUS_AUTH,
|
||||||
|
hostapd_acl_recv_radius, hapd))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct hostapd_acl_query_data *query, *prev;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
|
||||||
|
|
||||||
|
hostapd_acl_cache_free(hapd->acl_cache);
|
||||||
|
|
||||||
|
query = hapd->acl_queries;
|
||||||
|
while (query) {
|
||||||
|
prev = query;
|
||||||
|
query = query->next;
|
||||||
|
hostapd_acl_query_free(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_acl_reconfig(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *oldconf)
|
||||||
|
{
|
||||||
|
if (!hapd->radius_client_reconfigured)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hostapd_acl_deinit(hapd);
|
||||||
|
return hostapd_acl_init(hapd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
33
hostapd/ieee802_11_auth.h
Normal file
33
hostapd/ieee802_11_auth.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 authentication (ACL)
|
||||||
|
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_11_AUTH_H
|
||||||
|
#define IEEE802_11_AUTH_H
|
||||||
|
|
||||||
|
enum {
|
||||||
|
HOSTAPD_ACL_REJECT = 0,
|
||||||
|
HOSTAPD_ACL_ACCEPT = 1,
|
||||||
|
HOSTAPD_ACL_PENDING = 2,
|
||||||
|
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
|
const u8 *msg, size_t len, u32 *session_timeout,
|
||||||
|
u32 *acct_interim_interval, int *vlan_id);
|
||||||
|
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||||
|
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||||
|
int hostapd_acl_reconfig(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *oldconf);
|
||||||
|
|
||||||
|
#endif /* IEEE802_11_AUTH_H */
|
33
hostapd/ieee802_11h.c
Normal file
33
hostapd/ieee802_11h.c
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11h
|
||||||
|
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
|
||||||
|
|
||||||
|
int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len)
|
||||||
|
{
|
||||||
|
unsigned int max_pwr;
|
||||||
|
|
||||||
|
if (len < 2) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Too short power capability IE");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
max_pwr = power[1];
|
||||||
|
if (max_pwr > hapd->iface->sta_max_power)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
27
hostapd/ieee802_11h.h
Normal file
27
hostapd/ieee802_11h.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11h
|
||||||
|
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||||
|
* Copyright (c) 2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_11H_H
|
||||||
|
#define IEEE802_11H_H
|
||||||
|
|
||||||
|
#define SPECT_LOOSE_BINDING 1
|
||||||
|
#define SPECT_STRICT_BINDING 2
|
||||||
|
|
||||||
|
#define CHAN_SWITCH_MODE_NOISY 0
|
||||||
|
#define CHAN_SWITCH_MODE_QUIET 1
|
||||||
|
|
||||||
|
int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len);
|
||||||
|
|
||||||
|
#endif /* IEEE802_11H_H */
|
1971
hostapd/ieee802_1x.c
Normal file
1971
hostapd/ieee802_1x.c
Normal file
File diff suppressed because it is too large
Load diff
87
hostapd/ieee802_1x.h
Normal file
87
hostapd/ieee802_1x.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.1X-2004 Authenticator
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE802_1X_H
|
||||||
|
#define IEEE802_1X_H
|
||||||
|
|
||||||
|
struct hostapd_data;
|
||||||
|
struct sta_info;
|
||||||
|
struct eapol_state_machine;
|
||||||
|
struct hostapd_config;
|
||||||
|
struct hostapd_bss_config;
|
||||||
|
|
||||||
|
/* RFC 3580, 4. RC4 EAPOL-Key Frame */
|
||||||
|
|
||||||
|
struct ieee802_1x_eapol_key {
|
||||||
|
u8 type;
|
||||||
|
u16 key_length;
|
||||||
|
u8 replay_counter[8]; /* does not repeat within the life of the keying
|
||||||
|
* material used to encrypt the Key field;
|
||||||
|
* 64-bit NTP timestamp MAY be used here */
|
||||||
|
u8 key_iv[16]; /* cryptographically random number */
|
||||||
|
u8 key_index; /* key flag in the most significant bit:
|
||||||
|
* 0 = broadcast (default key),
|
||||||
|
* 1 = unicast (key mapping key); key index is in the
|
||||||
|
* 7 least significant bits */
|
||||||
|
u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
|
||||||
|
* MS-MPPE-Send-Key as the key */
|
||||||
|
|
||||||
|
/* followed by key: if packet body length = 44 + key length, then the
|
||||||
|
* key field (of key_length bytes) contains the key in encrypted form;
|
||||||
|
* if packet body length = 44, key field is absent and key_length
|
||||||
|
* represents the number of least significant octets from
|
||||||
|
* MS-MPPE-Send-Key attribute to be used as the keying material;
|
||||||
|
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
|
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||||
|
size_t len);
|
||||||
|
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ieee802_1x_free_station(struct sta_info *sta);
|
||||||
|
|
||||||
|
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, int authorized);
|
||||||
|
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
|
||||||
|
int ieee802_1x_init(struct hostapd_data *hapd);
|
||||||
|
void ieee802_1x_deinit(struct hostapd_data *hapd);
|
||||||
|
int ieee802_1x_reconfig(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss);
|
||||||
|
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u8 *buf, size_t len, int ack);
|
||||||
|
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
|
||||||
|
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
|
||||||
|
int idx);
|
||||||
|
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
|
||||||
|
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||||
|
int enabled);
|
||||||
|
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||||
|
int valid);
|
||||||
|
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
|
||||||
|
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
|
||||||
|
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
char *buf, size_t buflen);
|
||||||
|
void hostapd_get_ntp_timestamp(u8 *buf);
|
||||||
|
char *eap_type_text(u8 type);
|
||||||
|
|
||||||
|
struct radius_class_data;
|
||||||
|
|
||||||
|
void ieee802_1x_free_radius_class(struct radius_class_data *class);
|
||||||
|
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
|
||||||
|
struct radius_class_data *src);
|
||||||
|
|
||||||
|
#endif /* IEEE802_1X_H */
|
9
hostapd/logwatch/README
Normal file
9
hostapd/logwatch/README
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Logwatch is a utility for analyzing system logs and provide a human
|
||||||
|
readable summary. This directory has a configuration file and a log
|
||||||
|
analyzer script for parsing hostapd system log entries for logwatch.
|
||||||
|
These files can be installed by copying them to following locations:
|
||||||
|
|
||||||
|
/etc/log.d/conf/services/hostapd.conf
|
||||||
|
/etc/log.d/scripts/services/hostapd
|
||||||
|
|
||||||
|
More information about logwatch is available from http://www.logwatch.org/
|
10
hostapd/logwatch/hostapd.conf
Normal file
10
hostapd/logwatch/hostapd.conf
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Logwatch configuration for hostapd
|
||||||
|
#
|
||||||
|
# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
|
||||||
|
# Distributed under the terms of the GNU General Public License v2
|
||||||
|
# Alternatively, this file may be distributed under the terms of the BSD License
|
||||||
|
|
||||||
|
Title = "hostapd"
|
||||||
|
LogFile = messages
|
||||||
|
*OnlyService = hostapd
|
||||||
|
*RemoveHeaders
|
180
hostapd/mlme.c
Normal file
180
hostapd/mlme.c
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 MLME
|
||||||
|
* Copyright 2003-2006, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "mlme.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const char * mlme_auth_alg_str(int alg)
|
||||||
|
{
|
||||||
|
switch (alg) {
|
||||||
|
case WLAN_AUTH_OPEN:
|
||||||
|
return "OPEN_SYSTEM";
|
||||||
|
case WLAN_AUTH_SHARED_KEY:
|
||||||
|
return "SHARED_KEY";
|
||||||
|
case WLAN_AUTH_FT:
|
||||||
|
return "FT";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlme_authenticate_indication - Report the establishment of an authentication
|
||||||
|
* relationship with a specific peer MAC entity
|
||||||
|
* @hapd: BSS data
|
||||||
|
* @sta: peer STA data
|
||||||
|
*
|
||||||
|
* MLME calls this function as a result of the establishment of an
|
||||||
|
* authentication relationship with a specific peer MAC entity that
|
||||||
|
* resulted from an authentication procedure that was initiated by
|
||||||
|
* that specific peer MAC entity.
|
||||||
|
*
|
||||||
|
* PeerSTAAddress = sta->addr
|
||||||
|
* AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
|
||||||
|
*/
|
||||||
|
void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
|
||||||
|
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
|
||||||
|
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||||
|
mlme_deletekeys_request(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlme_deauthenticate_indication - Report the invalidation of an
|
||||||
|
* authentication relationship with a specific peer MAC entity
|
||||||
|
* @hapd: BSS data
|
||||||
|
* @sta: Peer STA data
|
||||||
|
* @reason_code: ReasonCode from Deauthentication frame
|
||||||
|
*
|
||||||
|
* MLME calls this function as a result of the invalidation of an
|
||||||
|
* authentication relationship with a specific peer MAC entity.
|
||||||
|
*
|
||||||
|
* PeerSTAAddress = sta->addr
|
||||||
|
*/
|
||||||
|
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u16 reason_code)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
|
||||||
|
MAC2STR(sta->addr), reason_code);
|
||||||
|
mlme_deletekeys_request(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlme_associate_indication - Report the establishment of an association with
|
||||||
|
* a specific peer MAC entity
|
||||||
|
* @hapd: BSS data
|
||||||
|
* @sta: peer STA data
|
||||||
|
*
|
||||||
|
* MLME calls this function as a result of the establishment of an
|
||||||
|
* association with a specific peer MAC entity that resulted from an
|
||||||
|
* association procedure that was initiated by that specific peer MAC entity.
|
||||||
|
*
|
||||||
|
* PeerSTAAddress = sta->addr
|
||||||
|
*/
|
||||||
|
void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-ASSOCIATE.indication(" MACSTR ")",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||||
|
mlme_deletekeys_request(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlme_reassociate_indication - Report the establishment of an reassociation
|
||||||
|
* with a specific peer MAC entity
|
||||||
|
* @hapd: BSS data
|
||||||
|
* @sta: peer STA data
|
||||||
|
*
|
||||||
|
* MLME calls this function as a result of the establishment of an
|
||||||
|
* reassociation with a specific peer MAC entity that resulted from a
|
||||||
|
* reassociation procedure that was initiated by that specific peer MAC entity.
|
||||||
|
*
|
||||||
|
* PeerSTAAddress = sta->addr
|
||||||
|
*
|
||||||
|
* sta->previous_ap contains the "Current AP" information from ReassocReq.
|
||||||
|
*/
|
||||||
|
void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-REASSOCIATE.indication(" MACSTR ")",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||||
|
mlme_deletekeys_request(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mlme_disassociate_indication - Report disassociation with a specific peer
|
||||||
|
* MAC entity
|
||||||
|
* @hapd: BSS data
|
||||||
|
* @sta: Peer STA data
|
||||||
|
* @reason_code: ReasonCode from Disassociation frame
|
||||||
|
*
|
||||||
|
* MLME calls this function as a result of the invalidation of an association
|
||||||
|
* relationship with a specific peer MAC entity.
|
||||||
|
*
|
||||||
|
* PeerSTAAddress = sta->addr
|
||||||
|
*/
|
||||||
|
void mlme_disassociate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u16 reason_code)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
|
||||||
|
MAC2STR(sta->addr), reason_code);
|
||||||
|
mlme_deletekeys_request(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
|
||||||
|
const u8 *addr)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-MichaelMICFailure.indication(" MACSTR ")",
|
||||||
|
MAC2STR(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"MLME-DELETEKEYS.request(" MACSTR ")",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
if (sta->wpa_sm)
|
||||||
|
wpa_remove_ptk(sta->wpa_sm);
|
||||||
|
}
|
40
hostapd/mlme.h
Normal file
40
hostapd/mlme.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* hostapd / IEEE 802.11 MLME
|
||||||
|
* Copyright 2003, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright 2003-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MLME_H
|
||||||
|
#define MLME_H
|
||||||
|
|
||||||
|
void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta);
|
||||||
|
|
||||||
|
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u16 reason_code);
|
||||||
|
|
||||||
|
void mlme_associate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta);
|
||||||
|
|
||||||
|
void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta);
|
||||||
|
|
||||||
|
void mlme_disassociate_indication(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u16 reason_code);
|
||||||
|
|
||||||
|
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
|
||||||
|
const u8 *addr);
|
||||||
|
|
||||||
|
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
|
||||||
|
#endif /* MLME_H */
|
52
hostapd/nt_password_hash.c
Normal file
52
hostapd/nt_password_hash.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* hostapd - Plaintext password to NtPasswordHash
|
||||||
|
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "ms_funcs.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
unsigned char password_hash[16];
|
||||||
|
size_t i;
|
||||||
|
char *password, buf[64], *pos;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
password = argv[1];
|
||||||
|
else {
|
||||||
|
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||||
|
printf("Failed to read password\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
pos = buf;
|
||||||
|
while (*pos != '\0') {
|
||||||
|
if (*pos == '\r' || *pos == '\n') {
|
||||||
|
*pos = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
password = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
nt_password_hash((u8 *) password, strlen(password), password_hash);
|
||||||
|
for (i = 0; i < sizeof(password_hash); i++)
|
||||||
|
printf("%02x", password_hash[i]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
396
hostapd/peerkey.c
Normal file
396
hostapd/peerkey.c
Normal file
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
* hostapd - PeerKey for Direct Link Setup (DLS)
|
||||||
|
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "defs.h"
|
||||||
|
#include "wpa_auth_i.h"
|
||||||
|
#include "wpa_auth_ie.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_PEERKEY
|
||||||
|
|
||||||
|
static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||||
|
struct wpa_stsl_negotiation *neg = timeout_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO: ? */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wpa_stsl_search {
|
||||||
|
const u8 *addr;
|
||||||
|
struct wpa_state_machine *sm;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
|
||||||
|
{
|
||||||
|
struct wpa_stsl_search *search = ctx;
|
||||||
|
if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
|
||||||
|
search->sm = sm;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, const u8 *peer,
|
||||||
|
u16 mui, u16 error_type)
|
||||||
|
{
|
||||||
|
u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
|
||||||
|
u8 *pos;
|
||||||
|
struct rsn_error_kde error;
|
||||||
|
|
||||||
|
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||||
|
"Sending SMK Error");
|
||||||
|
|
||||||
|
pos = kde;
|
||||||
|
|
||||||
|
if (peer) {
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
|
||||||
|
NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
error.mui = host_to_be16(mui);
|
||||||
|
error.error_type = host_to_be16(error_type);
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
|
||||||
|
(u8 *) &error, sizeof(error), NULL, 0);
|
||||||
|
|
||||||
|
__wpa_send_eapol(wpa_auth, sm,
|
||||||
|
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||||
|
WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
|
||||||
|
NULL, NULL, kde, pos - kde, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||||
|
{
|
||||||
|
struct wpa_eapol_ie_parse kde;
|
||||||
|
struct wpa_stsl_search search;
|
||||||
|
u8 *buf, *pos;
|
||||||
|
size_t buf_len;
|
||||||
|
|
||||||
|
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||||
|
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
|
||||||
|
kde.mac_addr_len < ETH_ALEN) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
|
||||||
|
"SMK M1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initiator = sm->addr; Peer = kde.mac_addr */
|
||||||
|
|
||||||
|
search.addr = kde.mac_addr;
|
||||||
|
search.sm = NULL;
|
||||||
|
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||||
|
0 || search.sm == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||||
|
" aborted - STA not associated anymore",
|
||||||
|
MAC2STR(kde.mac_addr));
|
||||||
|
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||||
|
STK_ERR_STA_NR);
|
||||||
|
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
|
||||||
|
buf = os_malloc(buf_len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return;
|
||||||
|
/* Initiator RSN IE */
|
||||||
|
os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
|
||||||
|
pos = buf + kde.rsn_ie_len;
|
||||||
|
/* Initiator MAC Address */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* SMK M2:
|
||||||
|
* EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||||
|
* MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
|
||||||
|
"Sending SMK M2");
|
||||||
|
|
||||||
|
__wpa_send_eapol(wpa_auth, search.sm,
|
||||||
|
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||||
|
WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
|
||||||
|
NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
|
||||||
|
|
||||||
|
os_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm,
|
||||||
|
struct wpa_eapol_key *key,
|
||||||
|
struct wpa_eapol_ie_parse *kde,
|
||||||
|
const u8 *smk)
|
||||||
|
{
|
||||||
|
u8 *buf, *pos;
|
||||||
|
size_t buf_len;
|
||||||
|
u32 lifetime;
|
||||||
|
|
||||||
|
/* SMK M4:
|
||||||
|
* EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
|
||||||
|
* MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
|
||||||
|
* Lifetime KDE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||||
|
pos = buf = os_malloc(buf_len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Initiator MAC Address */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* Initiator Nonce */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* SMK with PNonce */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||||
|
key->key_nonce, WPA_NONCE_LEN);
|
||||||
|
|
||||||
|
/* Lifetime */
|
||||||
|
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||||
|
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||||
|
|
||||||
|
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||||
|
"Sending SMK M4");
|
||||||
|
|
||||||
|
__wpa_send_eapol(wpa_auth, sm,
|
||||||
|
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||||
|
WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
|
||||||
|
NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
|
||||||
|
|
||||||
|
os_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm,
|
||||||
|
struct wpa_eapol_key *key,
|
||||||
|
struct wpa_eapol_ie_parse *kde,
|
||||||
|
const u8 *smk, const u8 *peer)
|
||||||
|
{
|
||||||
|
u8 *buf, *pos;
|
||||||
|
size_t buf_len;
|
||||||
|
u32 lifetime;
|
||||||
|
|
||||||
|
/* SMK M5:
|
||||||
|
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
|
||||||
|
* MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
|
||||||
|
* Lifetime KDE))
|
||||||
|
*/
|
||||||
|
|
||||||
|
buf_len = kde->rsn_ie_len +
|
||||||
|
2 + RSN_SELECTOR_LEN + ETH_ALEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
|
||||||
|
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
|
||||||
|
pos = buf = os_malloc(buf_len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Peer RSN IE */
|
||||||
|
os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
|
||||||
|
pos = buf + kde->rsn_ie_len;
|
||||||
|
|
||||||
|
/* Peer MAC Address */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
|
||||||
|
|
||||||
|
/* PNonce */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
|
||||||
|
WPA_NONCE_LEN, NULL, 0);
|
||||||
|
|
||||||
|
/* SMK and INonce */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
|
||||||
|
kde->nonce, WPA_NONCE_LEN);
|
||||||
|
|
||||||
|
/* Lifetime */
|
||||||
|
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
|
||||||
|
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
|
||||||
|
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
|
||||||
|
|
||||||
|
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||||
|
"Sending SMK M5");
|
||||||
|
|
||||||
|
__wpa_send_eapol(wpa_auth, sm,
|
||||||
|
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
|
||||||
|
WPA_KEY_INFO_SMK_MESSAGE,
|
||||||
|
NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
|
||||||
|
|
||||||
|
os_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||||
|
{
|
||||||
|
struct wpa_eapol_ie_parse kde;
|
||||||
|
struct wpa_stsl_search search;
|
||||||
|
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
|
||||||
|
|
||||||
|
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||||
|
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kde.rsn_ie == NULL ||
|
||||||
|
kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||||
|
kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
|
||||||
|
"Nonce KDE in SMK M3");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Peer = sm->addr; Initiator = kde.mac_addr;
|
||||||
|
* Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
|
||||||
|
|
||||||
|
search.addr = kde.mac_addr;
|
||||||
|
search.sm = NULL;
|
||||||
|
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||||
|
0 || search.sm == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
|
||||||
|
" aborted - STA not associated anymore",
|
||||||
|
MAC2STR(kde.mac_addr));
|
||||||
|
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
|
||||||
|
STK_ERR_STA_NR);
|
||||||
|
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os_get_random(smk, PMK_LEN)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SMK = PRF-256(Random number, "SMK Derivation",
|
||||||
|
* AA || Time || INonce || PNonce)
|
||||||
|
*/
|
||||||
|
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
|
||||||
|
pos = buf + ETH_ALEN;
|
||||||
|
wpa_get_ntp_timestamp(pos);
|
||||||
|
pos += 8;
|
||||||
|
os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
|
||||||
|
pos += WPA_NONCE_LEN;
|
||||||
|
os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
|
||||||
|
sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
|
||||||
|
smk, PMK_LEN);
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
|
||||||
|
|
||||||
|
wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
|
||||||
|
wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
|
||||||
|
|
||||||
|
/* Authenticator does not need SMK anymore and it is required to forget
|
||||||
|
* it. */
|
||||||
|
os_memset(smk, 0, sizeof(*smk));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
|
||||||
|
{
|
||||||
|
struct wpa_eapol_ie_parse kde;
|
||||||
|
struct wpa_stsl_search search;
|
||||||
|
struct rsn_error_kde error;
|
||||||
|
u16 mui, error_type;
|
||||||
|
|
||||||
|
if (wpa_parse_kde_ies((const u8 *) (key + 1),
|
||||||
|
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
|
||||||
|
kde.error == NULL || kde.error_len < sizeof(error)) {
|
||||||
|
wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
|
||||||
|
"SMK Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search.addr = kde.mac_addr;
|
||||||
|
search.sm = NULL;
|
||||||
|
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
|
||||||
|
0 || search.sm == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
|
||||||
|
"associated for SMK Error message from " MACSTR,
|
||||||
|
MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memcpy(&error, kde.error, sizeof(error));
|
||||||
|
mui = be_to_host16(error.mui);
|
||||||
|
error_type = be_to_host16(error.error_type);
|
||||||
|
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
|
||||||
|
"STA reported SMK Error: Peer " MACSTR
|
||||||
|
" MUI %d Error Type %d",
|
||||||
|
MAC2STR(kde.mac_addr), mui, error_type);
|
||||||
|
|
||||||
|
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_stsl_negotiation *neg)
|
||||||
|
{
|
||||||
|
struct wpa_stsl_negotiation *pos, *prev;
|
||||||
|
|
||||||
|
if (wpa_auth == NULL)
|
||||||
|
return -1;
|
||||||
|
pos = wpa_auth->stsl_negotiations;
|
||||||
|
prev = NULL;
|
||||||
|
while (pos) {
|
||||||
|
if (pos == neg) {
|
||||||
|
if (prev)
|
||||||
|
prev->next = pos->next;
|
||||||
|
else
|
||||||
|
wpa_auth->stsl_negotiations = pos->next;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
|
||||||
|
os_free(pos);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prev = pos;
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_PEERKEY */
|
368
hostapd/pmksa_cache.c
Normal file
368
hostapd/pmksa_cache.c
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* hostapd - PMKSA cache for IEEE 802.11i RSN
|
||||||
|
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "ap.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "eapol_sm.h"
|
||||||
|
#include "pmksa_cache.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const int pmksa_cache_max_entries = 1024;
|
||||||
|
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||||
|
|
||||||
|
struct rsn_pmksa_cache {
|
||||||
|
#define PMKID_HASH_SIZE 128
|
||||||
|
#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
|
||||||
|
struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
|
||||||
|
struct rsn_pmksa_cache_entry *pmksa;
|
||||||
|
int pmksa_count;
|
||||||
|
|
||||||
|
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
|
||||||
|
void *ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rsn_pmkid - Calculate PMK identifier
|
||||||
|
* @pmk: Pairwise master key
|
||||||
|
* @pmk_len: Length of pmk in bytes
|
||||||
|
* @aa: Authenticator address
|
||||||
|
* @spa: Supplicant address
|
||||||
|
*
|
||||||
|
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
|
||||||
|
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
|
||||||
|
*/
|
||||||
|
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||||
|
u8 *pmkid)
|
||||||
|
{
|
||||||
|
char *title = "PMK Name";
|
||||||
|
const u8 *addr[3];
|
||||||
|
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
|
||||||
|
unsigned char hash[SHA1_MAC_LEN];
|
||||||
|
|
||||||
|
addr[0] = (u8 *) title;
|
||||||
|
addr[1] = aa;
|
||||||
|
addr[2] = spa;
|
||||||
|
|
||||||
|
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
|
||||||
|
os_memcpy(pmkid, hash, PMKID_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
|
||||||
|
|
||||||
|
|
||||||
|
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
|
||||||
|
{
|
||||||
|
if (entry == NULL)
|
||||||
|
return;
|
||||||
|
os_free(entry->identity);
|
||||||
|
ieee802_1x_free_radius_class(&entry->radius_class);
|
||||||
|
os_free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||||
|
struct rsn_pmksa_cache_entry *entry)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache_entry *pos, *prev;
|
||||||
|
|
||||||
|
pmksa->pmksa_count--;
|
||||||
|
pmksa->free_cb(entry, pmksa->ctx);
|
||||||
|
pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
|
||||||
|
prev = NULL;
|
||||||
|
while (pos) {
|
||||||
|
if (pos == entry) {
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->hnext = pos->hnext;
|
||||||
|
} else {
|
||||||
|
pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
|
||||||
|
pos->hnext;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = pos;
|
||||||
|
pos = pos->hnext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = pmksa->pmksa;
|
||||||
|
prev = NULL;
|
||||||
|
while (pos) {
|
||||||
|
if (pos == entry) {
|
||||||
|
if (prev != NULL)
|
||||||
|
prev->next = pos->next;
|
||||||
|
else
|
||||||
|
pmksa->pmksa = pos->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = pos;
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
_pmksa_cache_free_entry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache *pmksa = eloop_ctx;
|
||||||
|
struct os_time now;
|
||||||
|
|
||||||
|
os_get_time(&now);
|
||||||
|
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
|
||||||
|
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
|
||||||
|
pmksa->pmksa = entry->next;
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
|
||||||
|
MACSTR, MAC2STR(entry->spa));
|
||||||
|
pmksa_cache_free_entry(pmksa, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
pmksa_cache_set_expiration(pmksa);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
|
||||||
|
{
|
||||||
|
int sec;
|
||||||
|
struct os_time now;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
|
||||||
|
if (pmksa->pmksa == NULL)
|
||||||
|
return;
|
||||||
|
os_get_time(&now);
|
||||||
|
sec = pmksa->pmksa->expiration - now.sec;
|
||||||
|
if (sec < 0)
|
||||||
|
sec = 0;
|
||||||
|
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||||
|
struct eapol_state_machine *eapol)
|
||||||
|
{
|
||||||
|
if (eapol == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (eapol->identity) {
|
||||||
|
entry->identity = os_malloc(eapol->identity_len);
|
||||||
|
if (entry->identity) {
|
||||||
|
entry->identity_len = eapol->identity_len;
|
||||||
|
os_memcpy(entry->identity, eapol->identity,
|
||||||
|
eapol->identity_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee802_1x_copy_radius_class(&entry->radius_class,
|
||||||
|
&eapol->radius_class);
|
||||||
|
|
||||||
|
entry->eap_type_authsrv = eapol->eap_type_authsrv;
|
||||||
|
entry->vlan_id = eapol->sta->vlan_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||||
|
struct eapol_state_machine *eapol)
|
||||||
|
{
|
||||||
|
if (entry == NULL || eapol == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (entry->identity) {
|
||||||
|
os_free(eapol->identity);
|
||||||
|
eapol->identity = os_malloc(entry->identity_len);
|
||||||
|
if (eapol->identity) {
|
||||||
|
eapol->identity_len = entry->identity_len;
|
||||||
|
os_memcpy(eapol->identity, entry->identity,
|
||||||
|
entry->identity_len);
|
||||||
|
}
|
||||||
|
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
|
||||||
|
eapol->identity, eapol->identity_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee802_1x_free_radius_class(&eapol->radius_class);
|
||||||
|
ieee802_1x_copy_radius_class(&eapol->radius_class,
|
||||||
|
&entry->radius_class);
|
||||||
|
if (eapol->radius_class.attr) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
|
||||||
|
"PMKSA", (unsigned long) eapol->radius_class.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
eapol->eap_type_authsrv = entry->eap_type_authsrv;
|
||||||
|
eapol->sta->vlan_id = entry->vlan_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pmksa_cache_add - Add a PMKSA cache entry
|
||||||
|
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||||
|
* @pmk: The new pairwise master key
|
||||||
|
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
|
||||||
|
* @aa: Authenticator address
|
||||||
|
* @spa: Supplicant address
|
||||||
|
* @session_timeout: Session timeout
|
||||||
|
* @eapol: Pointer to EAPOL state machine data
|
||||||
|
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
|
||||||
|
*
|
||||||
|
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
|
||||||
|
* cache. If an old entry is already in the cache for the same Supplicant,
|
||||||
|
* this entry will be replaced with the new entry. PMKID will be calculated
|
||||||
|
* based on the PMK.
|
||||||
|
*/
|
||||||
|
struct rsn_pmksa_cache_entry *
|
||||||
|
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
|
||||||
|
const u8 *aa, const u8 *spa, int session_timeout,
|
||||||
|
struct eapol_state_machine *eapol)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
|
||||||
|
struct os_time now;
|
||||||
|
|
||||||
|
if (pmk_len > PMK_LEN)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry = os_zalloc(sizeof(*entry));
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
os_memcpy(entry->pmk, pmk, pmk_len);
|
||||||
|
entry->pmk_len = pmk_len;
|
||||||
|
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
|
||||||
|
os_get_time(&now);
|
||||||
|
entry->expiration = now.sec;
|
||||||
|
if (session_timeout > 0)
|
||||||
|
entry->expiration += session_timeout;
|
||||||
|
else
|
||||||
|
entry->expiration += dot11RSNAConfigPMKLifetime;
|
||||||
|
entry->akmp = WPA_KEY_MGMT_IEEE8021X;
|
||||||
|
os_memcpy(entry->spa, spa, ETH_ALEN);
|
||||||
|
pmksa_cache_from_eapol_data(entry, eapol);
|
||||||
|
|
||||||
|
/* Replace an old entry for the same STA (if found) with the new entry
|
||||||
|
*/
|
||||||
|
pos = pmksa_cache_get(pmksa, spa, NULL);
|
||||||
|
if (pos)
|
||||||
|
pmksa_cache_free_entry(pmksa, pos);
|
||||||
|
|
||||||
|
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
|
||||||
|
/* Remove the oldest entry to make room for the new entry */
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
|
||||||
|
"entry (for " MACSTR ") to make room for new one",
|
||||||
|
MAC2STR(pmksa->pmksa->spa));
|
||||||
|
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the new entry; order by expiration time */
|
||||||
|
pos = pmksa->pmksa;
|
||||||
|
prev = NULL;
|
||||||
|
while (pos) {
|
||||||
|
if (pos->expiration > entry->expiration)
|
||||||
|
break;
|
||||||
|
prev = pos;
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
if (prev == NULL) {
|
||||||
|
entry->next = pmksa->pmksa;
|
||||||
|
pmksa->pmksa = entry;
|
||||||
|
} else {
|
||||||
|
entry->next = prev->next;
|
||||||
|
prev->next = entry;
|
||||||
|
}
|
||||||
|
entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
|
||||||
|
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
|
||||||
|
|
||||||
|
pmksa->pmksa_count++;
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
|
||||||
|
MAC2STR(entry->spa));
|
||||||
|
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pmksa_cache_deinit - Free all entries in PMKSA cache
|
||||||
|
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||||
|
*/
|
||||||
|
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache_entry *entry, *prev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pmksa == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entry = pmksa->pmksa;
|
||||||
|
while (entry) {
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
_pmksa_cache_free_entry(prev);
|
||||||
|
}
|
||||||
|
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
|
||||||
|
for (i = 0; i < PMKID_HASH_SIZE; i++)
|
||||||
|
pmksa->pmkid[i] = NULL;
|
||||||
|
os_free(pmksa);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pmksa_cache_get - Fetch a PMKSA cache entry
|
||||||
|
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
|
||||||
|
* @spa: Supplicant address or %NULL to match any
|
||||||
|
* @pmkid: PMKID or %NULL to match any
|
||||||
|
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
|
||||||
|
*/
|
||||||
|
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
|
||||||
|
const u8 *spa, const u8 *pmkid)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache_entry *entry;
|
||||||
|
|
||||||
|
if (pmkid)
|
||||||
|
entry = pmksa->pmkid[PMKID_HASH(pmkid)];
|
||||||
|
else
|
||||||
|
entry = pmksa->pmksa;
|
||||||
|
while (entry) {
|
||||||
|
if ((spa == NULL ||
|
||||||
|
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
|
||||||
|
(pmkid == NULL ||
|
||||||
|
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
|
||||||
|
return entry;
|
||||||
|
entry = pmkid ? entry->hnext : entry->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pmksa_cache_init - Initialize PMKSA cache
|
||||||
|
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
|
||||||
|
* @ctx: Context pointer for free_cb function
|
||||||
|
* Returns: Pointer to PMKSA cache data or %NULL on failure
|
||||||
|
*/
|
||||||
|
struct rsn_pmksa_cache *
|
||||||
|
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||||
|
void *ctx), void *ctx)
|
||||||
|
{
|
||||||
|
struct rsn_pmksa_cache *pmksa;
|
||||||
|
|
||||||
|
pmksa = os_zalloc(sizeof(*pmksa));
|
||||||
|
if (pmksa) {
|
||||||
|
pmksa->free_cb = free_cb;
|
||||||
|
pmksa->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pmksa;
|
||||||
|
}
|
54
hostapd/pmksa_cache.h
Normal file
54
hostapd/pmksa_cache.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* hostapd - PMKSA cache for IEEE 802.11i RSN
|
||||||
|
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PMKSA_CACHE_H
|
||||||
|
#define PMKSA_CACHE_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rsn_pmksa_cache_entry - PMKSA cache entry
|
||||||
|
*/
|
||||||
|
struct rsn_pmksa_cache_entry {
|
||||||
|
struct rsn_pmksa_cache_entry *next, *hnext;
|
||||||
|
u8 pmkid[PMKID_LEN];
|
||||||
|
u8 pmk[PMK_LEN];
|
||||||
|
size_t pmk_len;
|
||||||
|
os_time_t expiration;
|
||||||
|
int akmp; /* WPA_KEY_MGMT_* */
|
||||||
|
u8 spa[ETH_ALEN];
|
||||||
|
|
||||||
|
u8 *identity;
|
||||||
|
size_t identity_len;
|
||||||
|
struct radius_class_data radius_class;
|
||||||
|
u8 eap_type_authsrv;
|
||||||
|
int vlan_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rsn_pmksa_cache;
|
||||||
|
|
||||||
|
struct rsn_pmksa_cache *
|
||||||
|
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||||
|
void *ctx), void *ctx);
|
||||||
|
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
|
||||||
|
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
|
||||||
|
const u8 *spa, const u8 *pmkid);
|
||||||
|
struct rsn_pmksa_cache_entry *
|
||||||
|
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
|
||||||
|
const u8 *aa, const u8 *spa, int session_timeout,
|
||||||
|
struct eapol_state_machine *eapol);
|
||||||
|
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||||
|
struct eapol_state_machine *eapol);
|
||||||
|
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
|
||||||
|
u8 *pmkid);
|
||||||
|
|
||||||
|
#endif /* PMKSA_CACHE_H */
|
275
hostapd/preauth.c
Normal file
275
hostapd/preauth.c
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/*
|
||||||
|
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
|
||||||
|
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_RSN_PREAUTH
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "l2_packet/l2_packet.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "wpa_common.h"
|
||||||
|
#include "eapol_sm.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "preauth.h"
|
||||||
|
|
||||||
|
#ifndef ETH_P_PREAUTH
|
||||||
|
#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
|
||||||
|
#endif /* ETH_P_PREAUTH */
|
||||||
|
|
||||||
|
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||||
|
|
||||||
|
struct rsn_preauth_interface {
|
||||||
|
struct rsn_preauth_interface *next;
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
struct l2_packet_data *l2;
|
||||||
|
char *ifname;
|
||||||
|
int ifindex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||||
|
const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct rsn_preauth_interface *piface = ctx;
|
||||||
|
struct hostapd_data *hapd = piface->hapd;
|
||||||
|
struct ieee802_1x_hdr *hdr;
|
||||||
|
struct sta_info *sta;
|
||||||
|
struct l2_ethhdr *ethhdr;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
|
||||||
|
"from interface '%s'", piface->ifname);
|
||||||
|
if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
|
||||||
|
"(len=%lu)", (unsigned long) len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethhdr = (struct l2_ethhdr *) buf;
|
||||||
|
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
|
||||||
|
|
||||||
|
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
|
||||||
|
MACSTR, MAC2STR(ethhdr->h_dest));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, ethhdr->h_source);
|
||||||
|
if (sta && (sta->flags & WLAN_STA_ASSOC)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
|
||||||
|
"STA " MACSTR, MAC2STR(sta->addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
|
||||||
|
sta = ap_sta_add(hapd, ethhdr->h_source);
|
||||||
|
if (sta == NULL)
|
||||||
|
return;
|
||||||
|
sta->flags = WLAN_STA_PREAUTH;
|
||||||
|
|
||||||
|
ieee802_1x_new_station(hapd, sta);
|
||||||
|
if (sta->eapol_sm == NULL) {
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
sta = NULL;
|
||||||
|
} else {
|
||||||
|
sta->eapol_sm->radius_identifier = -1;
|
||||||
|
sta->eapol_sm->portValid = TRUE;
|
||||||
|
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sta == NULL)
|
||||||
|
return;
|
||||||
|
sta->preauth_iface = piface;
|
||||||
|
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
|
||||||
|
len - sizeof(*ethhdr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
|
||||||
|
{
|
||||||
|
struct rsn_preauth_interface *piface;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
|
||||||
|
|
||||||
|
piface = os_zalloc(sizeof(*piface));
|
||||||
|
if (piface == NULL)
|
||||||
|
return -1;
|
||||||
|
piface->hapd = hapd;
|
||||||
|
|
||||||
|
piface->ifname = os_strdup(ifname);
|
||||||
|
if (piface->ifname == NULL) {
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
|
||||||
|
rsn_preauth_receive, piface, 1);
|
||||||
|
if (piface->l2 == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
|
||||||
|
"to ETH_P_PREAUTH");
|
||||||
|
goto fail2;
|
||||||
|
}
|
||||||
|
|
||||||
|
piface->next = hapd->preauth_iface;
|
||||||
|
hapd->preauth_iface = piface;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail2:
|
||||||
|
os_free(piface->ifname);
|
||||||
|
fail1:
|
||||||
|
os_free(piface);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct rsn_preauth_interface *piface, *prev;
|
||||||
|
|
||||||
|
piface = hapd->preauth_iface;
|
||||||
|
hapd->preauth_iface = NULL;
|
||||||
|
while (piface) {
|
||||||
|
prev = piface;
|
||||||
|
piface = piface->next;
|
||||||
|
l2_packet_deinit(prev->l2);
|
||||||
|
os_free(prev->ifname);
|
||||||
|
os_free(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rsn_preauth_iface_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
char *tmp, *start, *end;
|
||||||
|
|
||||||
|
if (hapd->conf->rsn_preauth_interfaces == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
|
||||||
|
if (tmp == NULL)
|
||||||
|
return -1;
|
||||||
|
start = tmp;
|
||||||
|
for (;;) {
|
||||||
|
while (*start == ' ')
|
||||||
|
start++;
|
||||||
|
if (*start == '\0')
|
||||||
|
break;
|
||||||
|
end = os_strchr(start, ' ');
|
||||||
|
if (end)
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
if (rsn_preauth_iface_add(hapd, start)) {
|
||||||
|
rsn_preauth_iface_deinit(hapd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
start = end + 1;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
os_free(tmp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
|
||||||
|
MACSTR, MAC2STR(sta->addr));
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int success)
|
||||||
|
{
|
||||||
|
const u8 *key;
|
||||||
|
size_t len;
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||||
|
HOSTAPD_LEVEL_INFO, "pre-authentication %s",
|
||||||
|
success ? "succeeded" : "failed");
|
||||||
|
|
||||||
|
key = ieee802_1x_get_key(sta->eapol_sm, &len);
|
||||||
|
if (len > PMK_LEN)
|
||||||
|
len = PMK_LEN;
|
||||||
|
if (success && key) {
|
||||||
|
if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
|
||||||
|
sta->addr,
|
||||||
|
dot11RSNAConfigPMKLifetime,
|
||||||
|
sta->eapol_sm) == 0) {
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"added PMKSA cache entry (pre-auth)");
|
||||||
|
} else {
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||||
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
"failed to add PMKSA cache entry "
|
||||||
|
"(pre-auth)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish STA entry removal from timeout in order to avoid freeing
|
||||||
|
* STA data before the caller has finished processing.
|
||||||
|
*/
|
||||||
|
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct rsn_preauth_interface *piface;
|
||||||
|
struct l2_ethhdr *ethhdr;
|
||||||
|
|
||||||
|
piface = hapd->preauth_iface;
|
||||||
|
while (piface) {
|
||||||
|
if (piface == sta->preauth_iface)
|
||||||
|
break;
|
||||||
|
piface = piface->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (piface == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
|
||||||
|
"interface for " MACSTR, MAC2STR(sta->addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ethhdr = os_malloc(sizeof(*ethhdr) + len);
|
||||||
|
if (ethhdr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
|
||||||
|
os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
|
||||||
|
ethhdr->h_proto = htons(ETH_P_PREAUTH);
|
||||||
|
os_memcpy(ethhdr + 1, buf, len);
|
||||||
|
|
||||||
|
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
|
||||||
|
sizeof(*ethhdr) + len) < 0) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
|
||||||
|
"l2_packet_send\n");
|
||||||
|
}
|
||||||
|
os_free(ethhdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_RSN_PREAUTH */
|
58
hostapd/preauth.h
Normal file
58
hostapd/preauth.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
|
||||||
|
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PREAUTH_H
|
||||||
|
#define PREAUTH_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_RSN_PREAUTH
|
||||||
|
|
||||||
|
int rsn_preauth_iface_init(struct hostapd_data *hapd);
|
||||||
|
void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
|
||||||
|
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int success);
|
||||||
|
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u8 *buf, size_t len);
|
||||||
|
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
|
||||||
|
#else /* CONFIG_RSN_PREAUTH */
|
||||||
|
|
||||||
|
static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rsn_preauth_finished(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta,
|
||||||
|
int success)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rsn_preauth_send(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta,
|
||||||
|
u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_RSN_PREAUTH */
|
||||||
|
|
||||||
|
#endif /* PREAUTH_H */
|
177
hostapd/prism54.h
Normal file
177
hostapd/prism54.h
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
#ifndef PRISM54_H
|
||||||
|
#define PRISM54_H
|
||||||
|
|
||||||
|
struct ieee802_3_hdr_s {
|
||||||
|
unsigned char da[6];
|
||||||
|
unsigned char sa[6];
|
||||||
|
unsigned short type;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
typedef struct ieee802_3_hdr_s ieee802_3_hdr;
|
||||||
|
|
||||||
|
#define PIMOP_GET 0
|
||||||
|
#define PIMOP_SET 1
|
||||||
|
#define PIMOP_RESPONSE 2
|
||||||
|
#define PIMOP_ERROR 3
|
||||||
|
#define PIMOP_TRAP 4
|
||||||
|
|
||||||
|
struct pimdev_hdr_s {
|
||||||
|
int op;
|
||||||
|
unsigned long oid;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
typedef struct pimdev_hdr_s pimdev_hdr;
|
||||||
|
|
||||||
|
#define DOT11_OID_ATTACHMENT 0x19000003
|
||||||
|
|
||||||
|
/* really need to check */
|
||||||
|
#define DOT11_PKT_BEACON 0x80
|
||||||
|
#define DOT11_PKT_ASSOC_RESP 0x10
|
||||||
|
#define DOT11_PKT_REASSOC_RESP 0x30
|
||||||
|
#define DOT11_PKT_PROBE_RESP 0x50
|
||||||
|
|
||||||
|
struct obj_attachment_hdr {
|
||||||
|
char type;
|
||||||
|
char reserved;
|
||||||
|
short id;
|
||||||
|
short size;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct obj_attachment {
|
||||||
|
char type;
|
||||||
|
char reserved;
|
||||||
|
short id;
|
||||||
|
short size;
|
||||||
|
char data[1];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_MLMEAUTOLEVEL 0x19000001
|
||||||
|
#define DOT11_MLME_AUTO 0
|
||||||
|
#define DOT11_MLME_INTERMEDIATE 0x01000000
|
||||||
|
#define DOT11_MLME_EXTENDED 0x02000000
|
||||||
|
|
||||||
|
#define DOT11_OID_DEAUTHENTICATE 0x18000000
|
||||||
|
#define DOT11_OID_AUTHENTICATE 0x18000001
|
||||||
|
#define DOT11_OID_DISASSOCIATE 0x18000002
|
||||||
|
#define DOT11_OID_ASSOCIATE 0x18000003
|
||||||
|
#define DOT11_OID_BEACON 0x18000005
|
||||||
|
#define DOT11_OID_PROBE 0x18000006
|
||||||
|
#define DOT11_OID_REASSOCIATE 0x1800000b
|
||||||
|
|
||||||
|
struct obj_mlme {
|
||||||
|
char address[6];
|
||||||
|
short id;
|
||||||
|
short state;
|
||||||
|
short code;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_DEAUTHENTICATEEX 0x18000007
|
||||||
|
#define DOT11_OID_AUTHENTICATEEX 0x18000008
|
||||||
|
#define DOT11_OID_DISASSOCIATEEX 0x18000009
|
||||||
|
#define DOT11_OID_ASSOCIATEEX 0x1800000a
|
||||||
|
#define DOT11_OID_REASSOCIATEEX 0x1800000c
|
||||||
|
|
||||||
|
struct obj_mlmeex {
|
||||||
|
char address[6];
|
||||||
|
short id;
|
||||||
|
short state;
|
||||||
|
short code;
|
||||||
|
short size;
|
||||||
|
char data[1];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_STAKEY 0x12000008
|
||||||
|
|
||||||
|
#define DOT11_PRIV_WEP 0
|
||||||
|
#define DOT11_PRIV_TKIP 1
|
||||||
|
|
||||||
|
/* endian reversed to bigger endian */
|
||||||
|
#define DOT11_STAKEY_OPTION_DEFAULTKEY 0x100
|
||||||
|
|
||||||
|
struct obj_stakey {
|
||||||
|
char address[6];
|
||||||
|
char keyid;
|
||||||
|
char reserved;
|
||||||
|
short options;
|
||||||
|
char type;
|
||||||
|
char length;
|
||||||
|
char key[32];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_DEFKEYID 0x12000003
|
||||||
|
#define DOT11_OID_DEFKEY1 0x12000004
|
||||||
|
#define DOT11_OID_DEFKEY2 0x12000005
|
||||||
|
#define DOT11_OID_DEFKEY3 0x12000006
|
||||||
|
#define DOT11_OID_DEFKEY4 0x12000007
|
||||||
|
|
||||||
|
struct obj_key {
|
||||||
|
char type;
|
||||||
|
char length;
|
||||||
|
char key[32];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_STASC 0x1200000a
|
||||||
|
|
||||||
|
struct obj_stasc {
|
||||||
|
char address[6];
|
||||||
|
char keyid;
|
||||||
|
char tx_sc;
|
||||||
|
unsigned long sc_high;
|
||||||
|
unsigned short sc_low;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_CLIENTS 0x15000001
|
||||||
|
#define DOT11_OID_CLIENTSASSOCIATED 0x15000002
|
||||||
|
#define DOT11_OID_CLIENTST 0x15000003
|
||||||
|
#define DOT11_OID_CLIENTEND 0x150007d9
|
||||||
|
#define DOT11_OID_CLIENTFIND 0x150007db
|
||||||
|
|
||||||
|
#define DOT11_NODE_UNKNOWN
|
||||||
|
#define DOT11_NODE_CLIENT
|
||||||
|
#define DOT11_NODE_AP
|
||||||
|
|
||||||
|
/* endian reversed to bigger endian */
|
||||||
|
#define DOT11_STATE_NONE 0
|
||||||
|
#define DOT11_STATE_AUTHING 0x100
|
||||||
|
#define DOT11_STATE_AUTH 0x200
|
||||||
|
#define DOT11_STATE_ASSOCING 0x300
|
||||||
|
#define DOT11_STATE_REASSOCING 0x400
|
||||||
|
#define DOT11_STATE_ASSOC 0x500
|
||||||
|
#define DOT11_STATE_WDS 0x600
|
||||||
|
|
||||||
|
struct obj_sta {
|
||||||
|
char address[6];
|
||||||
|
char pad[2];
|
||||||
|
char state;
|
||||||
|
char node;
|
||||||
|
short age;
|
||||||
|
char reserved1;
|
||||||
|
char rssi;
|
||||||
|
char rate;
|
||||||
|
char reserved2;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_SSID 0x10000002
|
||||||
|
#define DOT11_OID_SSIDOVERRIDE 0x10000006
|
||||||
|
|
||||||
|
struct obj_ssid {
|
||||||
|
char length;
|
||||||
|
char octets[33];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define DOT11_OID_EAPAUTHSTA 0x150007de
|
||||||
|
#define DOT11_OID_EAPUNAUTHSTA 0x150007df
|
||||||
|
/* not in 38801 datasheet??? */
|
||||||
|
#define DOT11_OID_DOT1XENABLE 0x150007e0
|
||||||
|
#define DOT11_OID_MICFAILURE 0x150007e1
|
||||||
|
#define DOT11_OID_AUTHENABLE 0x12000000
|
||||||
|
#define DOT11_OID_PRIVACYINVOKED 0x12000001
|
||||||
|
#define DOT11_OID_EXUNENCRYPTED 0x12000002
|
||||||
|
|
||||||
|
#define DOT11_AUTH_OS 0x01000000
|
||||||
|
#define DOT11_AUTH_SK 0x02000000
|
||||||
|
#define DOT11_AUTH_BOTH 0x03000000
|
||||||
|
|
||||||
|
#define DOT11_BOOL_TRUE 0x01000000
|
||||||
|
|
||||||
|
#endif /* PRISM54_H */
|
71
hostapd/priv_netlink.h
Normal file
71
hostapd/priv_netlink.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef PRIV_NETLINK_H
|
||||||
|
#define PRIV_NETLINK_H
|
||||||
|
|
||||||
|
/* Private copy of needed Linux netlink/rtnetlink definitions.
|
||||||
|
*
|
||||||
|
* This should be replaced with user space header once one is available with C
|
||||||
|
* library, etc..
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IFLA_IFNAME
|
||||||
|
#define IFLA_IFNAME 3
|
||||||
|
#endif
|
||||||
|
#ifndef IFLA_WIRELESS
|
||||||
|
#define IFLA_WIRELESS 11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NETLINK_ROUTE 0
|
||||||
|
#define RTMGRP_LINK 1
|
||||||
|
#define RTM_BASE 0x10
|
||||||
|
#define RTM_NEWLINK (RTM_BASE + 0)
|
||||||
|
#define RTM_DELLINK (RTM_BASE + 1)
|
||||||
|
|
||||||
|
#define NLMSG_ALIGNTO 4
|
||||||
|
#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
|
||||||
|
#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
||||||
|
#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
|
||||||
|
|
||||||
|
#define RTA_ALIGNTO 4
|
||||||
|
#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
|
||||||
|
#define RTA_OK(rta,len) \
|
||||||
|
((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
|
||||||
|
(rta)->rta_len <= (len))
|
||||||
|
#define RTA_NEXT(rta,attrlen) \
|
||||||
|
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
|
||||||
|
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
|
||||||
|
|
||||||
|
|
||||||
|
struct sockaddr_nl
|
||||||
|
{
|
||||||
|
sa_family_t nl_family;
|
||||||
|
unsigned short nl_pad;
|
||||||
|
u32 nl_pid;
|
||||||
|
u32 nl_groups;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nlmsghdr
|
||||||
|
{
|
||||||
|
u32 nlmsg_len;
|
||||||
|
u16 nlmsg_type;
|
||||||
|
u16 nlmsg_flags;
|
||||||
|
u32 nlmsg_seq;
|
||||||
|
u32 nlmsg_pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ifinfomsg
|
||||||
|
{
|
||||||
|
unsigned char ifi_family;
|
||||||
|
unsigned char __ifi_pad;
|
||||||
|
unsigned short ifi_type;
|
||||||
|
int ifi_index;
|
||||||
|
unsigned ifi_flags;
|
||||||
|
unsigned ifi_change;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rtattr
|
||||||
|
{
|
||||||
|
unsigned short rta_len;
|
||||||
|
unsigned short rta_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* PRIV_NETLINK_H */
|
287
hostapd/radiotap.c
Normal file
287
hostapd/radiotap.c
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* Radiotap parser
|
||||||
|
*
|
||||||
|
* Copyright 2007 Andy Green <andy@warmcat.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
|
||||||
|
* I only modified some things on top to ease syncing should bugs be found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "radiotap_iter.h"
|
||||||
|
|
||||||
|
#define le16_to_cpu le_to_host16
|
||||||
|
#define le32_to_cpu le_to_host32
|
||||||
|
#define __le32 uint32_t
|
||||||
|
#define ulong unsigned long
|
||||||
|
#define unlikely(cond) (cond)
|
||||||
|
#define get_unaligned(p) \
|
||||||
|
({ \
|
||||||
|
struct packed_dummy_struct { \
|
||||||
|
typeof(*(p)) __val; \
|
||||||
|
} __attribute__((packed)) *__ptr = (void *) (p); \
|
||||||
|
\
|
||||||
|
__ptr->__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* function prototypes and related defs are in radiotap_iter.h */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
|
||||||
|
* @iterator: radiotap_iterator to initialize
|
||||||
|
* @radiotap_header: radiotap header to parse
|
||||||
|
* @max_length: total length we can parse into (eg, whole packet length)
|
||||||
|
*
|
||||||
|
* Returns: 0 or a negative error code if there is a problem.
|
||||||
|
*
|
||||||
|
* This function initializes an opaque iterator struct which can then
|
||||||
|
* be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
|
||||||
|
* argument which is present in the header. It knows about extended
|
||||||
|
* present headers and handles them.
|
||||||
|
*
|
||||||
|
* How to use:
|
||||||
|
* call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
|
||||||
|
* struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
|
||||||
|
* checking for a good 0 return code. Then loop calling
|
||||||
|
* __ieee80211_radiotap_iterator_next()... it returns either 0,
|
||||||
|
* -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
|
||||||
|
* The iterator's @this_arg member points to the start of the argument
|
||||||
|
* associated with the current argument index that is present, which can be
|
||||||
|
* found in the iterator's @this_arg_index member. This arg index corresponds
|
||||||
|
* to the IEEE80211_RADIOTAP_... defines.
|
||||||
|
*
|
||||||
|
* Radiotap header length:
|
||||||
|
* You can find the CPU-endian total radiotap header length in
|
||||||
|
* iterator->max_length after executing ieee80211_radiotap_iterator_init()
|
||||||
|
* successfully.
|
||||||
|
*
|
||||||
|
* Alignment Gotcha:
|
||||||
|
* You must take care when dereferencing iterator.this_arg
|
||||||
|
* for multibyte types... the pointer is not aligned. Use
|
||||||
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
||||||
|
* iterator.this_arg for type "type" safely on all arches.
|
||||||
|
*
|
||||||
|
* Example code:
|
||||||
|
* See Documentation/networking/radiotap-headers.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ieee80211_radiotap_iterator_init(
|
||||||
|
struct ieee80211_radiotap_iterator *iterator,
|
||||||
|
struct ieee80211_radiotap_header *radiotap_header,
|
||||||
|
int max_length)
|
||||||
|
{
|
||||||
|
/* Linux only supports version 0 radiotap format */
|
||||||
|
if (radiotap_header->it_version)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* sanity check for allowed length and radiotap length field */
|
||||||
|
if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
iterator->rtheader = radiotap_header;
|
||||||
|
iterator->max_length = le16_to_cpu(get_unaligned(
|
||||||
|
&radiotap_header->it_len));
|
||||||
|
iterator->arg_index = 0;
|
||||||
|
iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
|
||||||
|
&radiotap_header->it_present));
|
||||||
|
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
|
||||||
|
iterator->this_arg = NULL;
|
||||||
|
|
||||||
|
/* find payload start allowing for extended bitmap(s) */
|
||||||
|
|
||||||
|
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
|
||||||
|
while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
|
||||||
|
(1<<IEEE80211_RADIOTAP_EXT)) {
|
||||||
|
iterator->arg += sizeof(u32);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for insanity where the present bitmaps
|
||||||
|
* keep claiming to extend up to or even beyond the
|
||||||
|
* stated radiotap header length
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((ulong)iterator->arg - (ulong)iterator->rtheader)
|
||||||
|
> (ulong)iterator->max_length)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator->arg += sizeof(u32);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no need to check again for blowing past stated radiotap
|
||||||
|
* header length, because ieee80211_radiotap_iterator_next
|
||||||
|
* checks it before it is dereferenced
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we are all initialized happily */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
|
||||||
|
* @iterator: radiotap_iterator to move to next arg (if any)
|
||||||
|
*
|
||||||
|
* Returns: 0 if there is an argument to handle,
|
||||||
|
* -ENOENT if there are no more args or -EINVAL
|
||||||
|
* if there is something else wrong.
|
||||||
|
*
|
||||||
|
* This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
|
||||||
|
* in @this_arg_index and sets @this_arg to point to the
|
||||||
|
* payload for the field. It takes care of alignment handling and extended
|
||||||
|
* present fields. @this_arg can be changed by the caller (eg,
|
||||||
|
* incremented to move inside a compound argument like
|
||||||
|
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
|
||||||
|
* little-endian format whatever the endianess of your CPU.
|
||||||
|
*
|
||||||
|
* Alignment Gotcha:
|
||||||
|
* You must take care when dereferencing iterator.this_arg
|
||||||
|
* for multibyte types... the pointer is not aligned. Use
|
||||||
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
||||||
|
* iterator.this_arg for type "type" safely on all arches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ieee80211_radiotap_iterator_next(
|
||||||
|
struct ieee80211_radiotap_iterator *iterator)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* small length lookup table for all radiotap types we heard of
|
||||||
|
* starting from b0 in the bitmap, so we can walk the payload
|
||||||
|
* area of the radiotap header
|
||||||
|
*
|
||||||
|
* There is a requirement to pad args, so that args
|
||||||
|
* of a given length must begin at a boundary of that length
|
||||||
|
* -- but note that compound args are allowed (eg, 2 x u16
|
||||||
|
* for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
|
||||||
|
* a reliable indicator of alignment requirement.
|
||||||
|
*
|
||||||
|
* upper nybble: content alignment for arg
|
||||||
|
* lower nybble: content length for arg
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const u8 rt_sizes[] = {
|
||||||
|
[IEEE80211_RADIOTAP_TSFT] = 0x88,
|
||||||
|
[IEEE80211_RADIOTAP_FLAGS] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_RATE] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_CHANNEL] = 0x24,
|
||||||
|
[IEEE80211_RADIOTAP_FHSS] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_ANTENNA] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
|
||||||
|
[IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
|
||||||
|
[IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
|
||||||
|
/*
|
||||||
|
* add more here as they are defined in
|
||||||
|
* include/net/ieee80211_radiotap.h
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for every radiotap entry we can at
|
||||||
|
* least skip (by knowing the length)...
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (iterator->arg_index < (int) sizeof(rt_sizes)) {
|
||||||
|
int hit = 0;
|
||||||
|
int pad;
|
||||||
|
|
||||||
|
if (!(iterator->bitmap_shifter & 1))
|
||||||
|
goto next_entry; /* arg not present */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arg is present, account for alignment padding
|
||||||
|
* 8-bit args can be at any alignment
|
||||||
|
* 16-bit args must start on 16-bit boundary
|
||||||
|
* 32-bit args must start on 32-bit boundary
|
||||||
|
* 64-bit args must start on 64-bit boundary
|
||||||
|
*
|
||||||
|
* note that total arg size can differ from alignment of
|
||||||
|
* elements inside arg, so we use upper nybble of length
|
||||||
|
* table to base alignment on
|
||||||
|
*
|
||||||
|
* also note: these alignments are ** relative to the
|
||||||
|
* start of the radiotap header **. There is no guarantee
|
||||||
|
* that the radiotap header itself is aligned on any
|
||||||
|
* kind of boundary.
|
||||||
|
*
|
||||||
|
* the above is why get_unaligned() is used to dereference
|
||||||
|
* multibyte elements from the radiotap area
|
||||||
|
*/
|
||||||
|
|
||||||
|
pad = (((ulong)iterator->arg) -
|
||||||
|
((ulong)iterator->rtheader)) &
|
||||||
|
((rt_sizes[iterator->arg_index] >> 4) - 1);
|
||||||
|
|
||||||
|
if (pad)
|
||||||
|
iterator->arg +=
|
||||||
|
(rt_sizes[iterator->arg_index] >> 4) - pad;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is what we will return to user, but we need to
|
||||||
|
* move on first so next call has something fresh to test
|
||||||
|
*/
|
||||||
|
iterator->this_arg_index = iterator->arg_index;
|
||||||
|
iterator->this_arg = iterator->arg;
|
||||||
|
hit = 1;
|
||||||
|
|
||||||
|
/* internally move on the size of this arg */
|
||||||
|
iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for insanity where we are given a bitmap that
|
||||||
|
* claims to have more arg content than the length of the
|
||||||
|
* radiotap section. We will normally end up equalling this
|
||||||
|
* max_length on the last arg, never exceeding it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
|
||||||
|
(ulong) iterator->max_length)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
next_entry:
|
||||||
|
iterator->arg_index++;
|
||||||
|
if (unlikely((iterator->arg_index & 31) == 0)) {
|
||||||
|
/* completed current u32 bitmap */
|
||||||
|
if (iterator->bitmap_shifter & 1) {
|
||||||
|
/* b31 was set, there is more */
|
||||||
|
/* move to next u32 bitmap */
|
||||||
|
iterator->bitmap_shifter = le32_to_cpu(
|
||||||
|
get_unaligned(iterator->next_bitmap));
|
||||||
|
iterator->next_bitmap++;
|
||||||
|
} else
|
||||||
|
/* no more bitmaps: end */
|
||||||
|
iterator->arg_index = sizeof(rt_sizes);
|
||||||
|
} else /* just try the next bit */
|
||||||
|
iterator->bitmap_shifter >>= 1;
|
||||||
|
|
||||||
|
/* if we found a valid arg earlier, return it now */
|
||||||
|
if (hit)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't know how to handle any more args, we're done */
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
242
hostapd/radiotap.h
Normal file
242
hostapd/radiotap.h
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
|
||||||
|
/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2003, 2004 David Young. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of David Young may not be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
|
||||||
|
* YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
* OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modifications to fit into the linux IEEE 802.11 stack,
|
||||||
|
* Mike Kershaw (dragorn@kismetwireless.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IEEE80211RADIOTAP_H
|
||||||
|
#define IEEE80211RADIOTAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Base version of the radiotap packet header data */
|
||||||
|
#define PKTHDR_RADIOTAP_VERSION 0
|
||||||
|
|
||||||
|
/* A generic radio capture format is desirable. There is one for
|
||||||
|
* Linux, but it is neither rigidly defined (there were not even
|
||||||
|
* units given for some fields) nor easily extensible.
|
||||||
|
*
|
||||||
|
* I suggest the following extensible radio capture format. It is
|
||||||
|
* based on a bitmap indicating which fields are present.
|
||||||
|
*
|
||||||
|
* I am trying to describe precisely what the application programmer
|
||||||
|
* should expect in the following, and for that reason I tell the
|
||||||
|
* units and origin of each measurement (where it applies), or else I
|
||||||
|
* use sufficiently weaselly language ("is a monotonically nondecreasing
|
||||||
|
* function of...") that I cannot set false expectations for lawyerly
|
||||||
|
* readers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The radio capture header precedes the 802.11 header.
|
||||||
|
* All data in the header is little endian on all platforms.
|
||||||
|
*/
|
||||||
|
struct ieee80211_radiotap_header {
|
||||||
|
uint8_t it_version; /* Version 0. Only increases
|
||||||
|
* for drastic changes,
|
||||||
|
* introduction of compatible
|
||||||
|
* new fields does not count.
|
||||||
|
*/
|
||||||
|
uint8_t it_pad;
|
||||||
|
uint16_t it_len; /* length of the whole
|
||||||
|
* header in bytes, including
|
||||||
|
* it_version, it_pad,
|
||||||
|
* it_len, and data fields.
|
||||||
|
*/
|
||||||
|
uint32_t it_present; /* A bitmap telling which
|
||||||
|
* fields are present. Set bit 31
|
||||||
|
* (0x80000000) to extend the
|
||||||
|
* bitmap by another 32 bits.
|
||||||
|
* Additional extensions are made
|
||||||
|
* by setting bit 31.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Name Data type Units
|
||||||
|
* ---- --------- -----
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_TSFT __le64 microseconds
|
||||||
|
*
|
||||||
|
* Value in microseconds of the MAC's 64-bit 802.11 Time
|
||||||
|
* Synchronization Function timer when the first bit of the
|
||||||
|
* MPDU arrived at the MAC. For received frames, only.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
|
||||||
|
*
|
||||||
|
* Tx/Rx frequency in MHz, followed by flags (see below).
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_FHSS uint16_t see below
|
||||||
|
*
|
||||||
|
* For frequency-hopping radios, the hop set (first byte)
|
||||||
|
* and pattern (second byte).
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_RATE u8 500kb/s
|
||||||
|
*
|
||||||
|
* Tx/Rx data rate
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
|
||||||
|
* one milliwatt (dBm)
|
||||||
|
*
|
||||||
|
* RF signal power at the antenna, decibel difference from
|
||||||
|
* one milliwatt.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
|
||||||
|
* one milliwatt (dBm)
|
||||||
|
*
|
||||||
|
* RF noise power at the antenna, decibel difference from one
|
||||||
|
* milliwatt.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
|
||||||
|
*
|
||||||
|
* RF signal power at the antenna, decibel difference from an
|
||||||
|
* arbitrary, fixed reference.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
|
||||||
|
*
|
||||||
|
* RF noise power at the antenna, decibel difference from an
|
||||||
|
* arbitrary, fixed reference point.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
|
||||||
|
*
|
||||||
|
* Quality of Barker code lock. Unitless. Monotonically
|
||||||
|
* nondecreasing with "better" lock strength. Called "Signal
|
||||||
|
* Quality" in datasheets. (Is there a standard way to measure
|
||||||
|
* this?)
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
|
||||||
|
*
|
||||||
|
* Transmit power expressed as unitless distance from max
|
||||||
|
* power set at factory calibration. 0 is max power.
|
||||||
|
* Monotonically nondecreasing with lower power levels.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
|
||||||
|
*
|
||||||
|
* Transmit power expressed as decibel distance from max power
|
||||||
|
* set at factory calibration. 0 is max power. Monotonically
|
||||||
|
* nondecreasing with lower power levels.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
|
||||||
|
* one milliwatt (dBm)
|
||||||
|
*
|
||||||
|
* Transmit power expressed as dBm (decibels from a 1 milliwatt
|
||||||
|
* reference). This is the absolute power level measured at
|
||||||
|
* the antenna port.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_FLAGS u8 bitmap
|
||||||
|
*
|
||||||
|
* Properties of transmitted and received frames. See flags
|
||||||
|
* defined below.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_ANTENNA u8 antenna index
|
||||||
|
*
|
||||||
|
* Unitless indication of the Rx/Tx antenna for this packet.
|
||||||
|
* The first antenna is antenna 0.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
|
||||||
|
*
|
||||||
|
* Properties of received frames. See flags defined below.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
|
||||||
|
*
|
||||||
|
* Properties of transmitted frames. See flags defined below.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_RTS_RETRIES u8 data
|
||||||
|
*
|
||||||
|
* Number of rts retries a transmitted frame used.
|
||||||
|
*
|
||||||
|
* IEEE80211_RADIOTAP_DATA_RETRIES u8 data
|
||||||
|
*
|
||||||
|
* Number of unicast retries a transmitted frame used.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum ieee80211_radiotap_type {
|
||||||
|
IEEE80211_RADIOTAP_TSFT = 0,
|
||||||
|
IEEE80211_RADIOTAP_FLAGS = 1,
|
||||||
|
IEEE80211_RADIOTAP_RATE = 2,
|
||||||
|
IEEE80211_RADIOTAP_CHANNEL = 3,
|
||||||
|
IEEE80211_RADIOTAP_FHSS = 4,
|
||||||
|
IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
|
||||||
|
IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
|
||||||
|
IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
|
||||||
|
IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
|
||||||
|
IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
|
||||||
|
IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
|
||||||
|
IEEE80211_RADIOTAP_ANTENNA = 11,
|
||||||
|
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
|
||||||
|
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
|
||||||
|
IEEE80211_RADIOTAP_RX_FLAGS = 14,
|
||||||
|
IEEE80211_RADIOTAP_TX_FLAGS = 15,
|
||||||
|
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
|
||||||
|
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
|
||||||
|
IEEE80211_RADIOTAP_EXT = 31
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Channel flags. */
|
||||||
|
#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
|
||||||
|
#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
|
||||||
|
#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
|
||||||
|
#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
|
||||||
|
#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
|
||||||
|
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
|
||||||
|
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
|
||||||
|
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
|
||||||
|
|
||||||
|
/* For IEEE80211_RADIOTAP_FLAGS */
|
||||||
|
#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
|
||||||
|
* during CFP
|
||||||
|
*/
|
||||||
|
#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
|
||||||
|
* with short
|
||||||
|
* preamble
|
||||||
|
*/
|
||||||
|
#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
|
||||||
|
* with WEP encryption
|
||||||
|
*/
|
||||||
|
#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
|
||||||
|
* with fragmentation
|
||||||
|
*/
|
||||||
|
#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
|
||||||
|
#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
|
||||||
|
* 802.11 header and payload
|
||||||
|
* (to 32-bit boundary)
|
||||||
|
*/
|
||||||
|
/* For IEEE80211_RADIOTAP_RX_FLAGS */
|
||||||
|
#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
|
||||||
|
|
||||||
|
/* For IEEE80211_RADIOTAP_TX_FLAGS */
|
||||||
|
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
|
||||||
|
* retries */
|
||||||
|
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
|
||||||
|
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
|
||||||
|
|
||||||
|
#endif /* IEEE80211_RADIOTAP_H */
|
41
hostapd/radiotap_iter.h
Normal file
41
hostapd/radiotap_iter.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef __RADIOTAP_ITER_H
|
||||||
|
#define __RADIOTAP_ITER_H
|
||||||
|
|
||||||
|
#include "radiotap.h"
|
||||||
|
|
||||||
|
/* Radiotap header iteration
|
||||||
|
* implemented in radiotap.c
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
|
||||||
|
* @rtheader: pointer to the radiotap header we are walking through
|
||||||
|
* @max_length: length of radiotap header in cpu byte ordering
|
||||||
|
* @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
|
||||||
|
* @this_arg: pointer to current radiotap arg
|
||||||
|
* @arg_index: internal next argument index
|
||||||
|
* @arg: internal next argument pointer
|
||||||
|
* @next_bitmap: internal pointer to next present u32
|
||||||
|
* @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ieee80211_radiotap_iterator {
|
||||||
|
struct ieee80211_radiotap_header *rtheader;
|
||||||
|
int max_length;
|
||||||
|
int this_arg_index;
|
||||||
|
unsigned char *this_arg;
|
||||||
|
|
||||||
|
int arg_index;
|
||||||
|
unsigned char *arg;
|
||||||
|
uint32_t *next_bitmap;
|
||||||
|
uint32_t bitmap_shifter;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int ieee80211_radiotap_iterator_init(
|
||||||
|
struct ieee80211_radiotap_iterator *iterator,
|
||||||
|
struct ieee80211_radiotap_header *radiotap_header,
|
||||||
|
int max_length);
|
||||||
|
|
||||||
|
extern int ieee80211_radiotap_iterator_next(
|
||||||
|
struct ieee80211_radiotap_iterator *iterator);
|
||||||
|
|
||||||
|
#endif /* __RADIOTAP_ITER_H */
|
712
hostapd/reconfig.c
Normal file
712
hostapd/reconfig.c
Normal file
|
@ -0,0 +1,712 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Configuration reloading
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
|
||||||
|
* Copyright (c) 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "radius/radius_client.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "iapp.h"
|
||||||
|
#include "ap_list.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "vlan_init.h"
|
||||||
|
#include "ieee802_11_auth.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "accounting.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hostapd_config_change - Configuration change information
|
||||||
|
* This is for two purposes:
|
||||||
|
* - Storing configuration information in the hostapd_iface during
|
||||||
|
* the asynchronous parts of reconfiguration.
|
||||||
|
* - Passing configuration information for per-station reconfiguration.
|
||||||
|
*/
|
||||||
|
struct hostapd_config_change {
|
||||||
|
struct hostapd_data *hapd;
|
||||||
|
struct hostapd_config *newconf, *oldconf;
|
||||||
|
struct hostapd_bss_config *newbss, *oldbss;
|
||||||
|
int mac_acl_changed;
|
||||||
|
int num_sta_remove; /* number of STAs that need to be removed */
|
||||||
|
int beacon_changed;
|
||||||
|
struct hostapd_iface *hapd_iface;
|
||||||
|
struct hostapd_data **new_hapd, **old_hapd;
|
||||||
|
int num_old_hapd;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_config_reload_sta(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, void *data)
|
||||||
|
{
|
||||||
|
struct hostapd_config_change *change = data;
|
||||||
|
struct hostapd_bss_config *newbss, *oldbss;
|
||||||
|
int deauth = 0;
|
||||||
|
u8 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
|
||||||
|
|
||||||
|
newbss = change->newbss;
|
||||||
|
oldbss = change->oldbss;
|
||||||
|
hapd = change->hapd;
|
||||||
|
|
||||||
|
if (sta->ssid == &oldbss->ssid) {
|
||||||
|
sta->ssid = &newbss->ssid;
|
||||||
|
|
||||||
|
if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
|
||||||
|
os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
|
||||||
|
newbss->ssid.ssid_len) != 0) {
|
||||||
|
/* main SSID was changed - kick STA out */
|
||||||
|
deauth++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sta->ssid_probe = sta->ssid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If MAC ACL configuration has changed, deauthenticate stations that
|
||||||
|
* have been removed from accepted list or have been added to denied
|
||||||
|
* list. If external RADIUS server is used for ACL, all stations are
|
||||||
|
* deauthenticated and they will need to authenticate again. This
|
||||||
|
* limits sudden load on the RADIUS server since the verification will
|
||||||
|
* be done over the time needed for the STAs to reauthenticate
|
||||||
|
* themselves.
|
||||||
|
*/
|
||||||
|
if (change->mac_acl_changed &&
|
||||||
|
(newbss->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH ||
|
||||||
|
!hostapd_allowed_address(hapd, sta->addr, NULL, 0, NULL, NULL,
|
||||||
|
NULL)))
|
||||||
|
deauth++;
|
||||||
|
|
||||||
|
if (newbss->ieee802_1x != oldbss->ieee802_1x &&
|
||||||
|
sta->ssid == &hapd->conf->ssid)
|
||||||
|
deauth++;
|
||||||
|
|
||||||
|
if (newbss->wpa != oldbss->wpa)
|
||||||
|
deauth++;
|
||||||
|
|
||||||
|
if (!newbss->wme_enabled && (sta->flags & WLAN_STA_WME))
|
||||||
|
deauth++;
|
||||||
|
|
||||||
|
if (newbss->auth_algs != oldbss->auth_algs &&
|
||||||
|
((sta->auth_alg == WLAN_AUTH_OPEN &&
|
||||||
|
!(newbss->auth_algs & WPA_AUTH_ALG_OPEN)) ||
|
||||||
|
(sta->auth_alg == WLAN_AUTH_SHARED_KEY &&
|
||||||
|
!(newbss->auth_algs & WPA_AUTH_ALG_SHARED))))
|
||||||
|
deauth++;
|
||||||
|
|
||||||
|
if (change->num_sta_remove > 0) {
|
||||||
|
deauth++;
|
||||||
|
reason = WLAN_REASON_DISASSOC_AP_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deauth) {
|
||||||
|
wpa_printf(MSG_DEBUG, "STA " MACSTR " deauthenticated during "
|
||||||
|
"config reloading (reason=%d)",
|
||||||
|
MAC2STR(sta->addr), reason);
|
||||||
|
ieee802_11_send_deauth(hapd, sta->addr, reason);
|
||||||
|
ap_sta_deauthenticate(hapd, sta, reason);
|
||||||
|
change->num_sta_remove--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_reconfig_tx_queue_params(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *newconf,
|
||||||
|
struct hostapd_config *oldconf)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct hostapd_tx_queue_params *o, *n;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_TX_QUEUES; i++) {
|
||||||
|
o = &oldconf->tx_queue[i];
|
||||||
|
n = &newconf->tx_queue[i];
|
||||||
|
|
||||||
|
if (!n->configured)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((n->aifs != o->aifs || n->cwmin != o->cwmin ||
|
||||||
|
n->cwmax != o->cwmax || n->burst != o->burst) &&
|
||||||
|
hostapd_set_tx_queue_params(hapd, i, n->aifs, n->cwmin,
|
||||||
|
n->cwmax, n->burst))
|
||||||
|
printf("Failed to set TX queue parameters for queue %d"
|
||||||
|
".\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_reconfig_wme(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_config *newconf,
|
||||||
|
struct hostapd_config *oldconf)
|
||||||
|
{
|
||||||
|
int beacon_changed = 0;
|
||||||
|
size_t i;
|
||||||
|
struct hostapd_wme_ac_params *o, *n;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(newconf->wme_ac_params) /
|
||||||
|
sizeof(newconf->wme_ac_params[0]); i++) {
|
||||||
|
o = &oldconf->wme_ac_params[i];
|
||||||
|
n = &newconf->wme_ac_params[i];
|
||||||
|
if (n->cwmin != o->cwmin ||
|
||||||
|
n->cwmax != o->cwmax ||
|
||||||
|
n->aifs != o->aifs ||
|
||||||
|
n->txopLimit != o->txopLimit ||
|
||||||
|
n->admission_control_mandatory !=
|
||||||
|
o->admission_control_mandatory) {
|
||||||
|
beacon_changed++;
|
||||||
|
hapd->parameter_set_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return beacon_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int rate_array_diff(int *a1, int *a2)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (a1 == NULL && a2 == NULL)
|
||||||
|
return 0;
|
||||||
|
if (a1 == NULL || a2 == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (;;) {
|
||||||
|
if (a1[i] != a2[i])
|
||||||
|
return 1;
|
||||||
|
if (a1[i] == -1)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int hostapd_acl_diff(struct hostapd_bss_config *a,
|
||||||
|
struct hostapd_bss_config *b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (a->macaddr_acl != b->macaddr_acl ||
|
||||||
|
a->num_accept_mac != b->num_accept_mac ||
|
||||||
|
a->num_deny_mac != b->num_deny_mac)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0; i < a->num_accept_mac; i++) {
|
||||||
|
if (os_memcmp(a->accept_mac[i], b->accept_mac[i], ETH_ALEN) !=
|
||||||
|
0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < a->num_deny_mac; i++) {
|
||||||
|
if (os_memcmp(a->deny_mac[i], b->deny_mac[i], ETH_ALEN) != 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reload_iface2 - Part 2 of reload_iface
|
||||||
|
* @hapd_iface: Pointer to hostapd interface data.
|
||||||
|
*/
|
||||||
|
static void reload_iface2(struct hostapd_iface *hapd_iface)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||||
|
struct hostapd_config *newconf = hapd_iface->change->newconf;
|
||||||
|
struct hostapd_config *oldconf = hapd_iface->change->oldconf;
|
||||||
|
int beacon_changed = hapd_iface->change->beacon_changed;
|
||||||
|
hostapd_iface_cb cb = hapd_iface->reload_iface_cb;
|
||||||
|
|
||||||
|
if (newconf->preamble != oldconf->preamble) {
|
||||||
|
if (hostapd_set_preamble(hapd, hapd->iconf->preamble))
|
||||||
|
printf("Could not set preamble for kernel driver\n");
|
||||||
|
beacon_changed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newconf->beacon_int != oldconf->beacon_int) {
|
||||||
|
/* Need to change beacon interval if it has changed or if
|
||||||
|
* auto channel selection was used. */
|
||||||
|
if (hostapd_set_beacon_int(hapd, newconf->beacon_int))
|
||||||
|
printf("Could not set beacon interval for kernel "
|
||||||
|
"driver\n");
|
||||||
|
if (newconf->beacon_int != oldconf->beacon_int)
|
||||||
|
beacon_changed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newconf->cts_protection_type != oldconf->cts_protection_type)
|
||||||
|
beacon_changed++;
|
||||||
|
|
||||||
|
if (newconf->rts_threshold > -1 &&
|
||||||
|
newconf->rts_threshold != oldconf->rts_threshold &&
|
||||||
|
hostapd_set_rts(hapd, newconf->rts_threshold))
|
||||||
|
printf("Could not set RTS threshold for kernel driver\n");
|
||||||
|
|
||||||
|
if (newconf->fragm_threshold > -1 &&
|
||||||
|
newconf->fragm_threshold != oldconf->fragm_threshold &&
|
||||||
|
hostapd_set_frag(hapd, newconf->fragm_threshold))
|
||||||
|
printf("Could not set fragmentation threshold for kernel "
|
||||||
|
"driver\n");
|
||||||
|
|
||||||
|
hostapd_reconfig_tx_queue_params(hapd, newconf, oldconf);
|
||||||
|
|
||||||
|
if (hostapd_reconfig_wme(hapd, newconf, oldconf) > 0)
|
||||||
|
beacon_changed++;
|
||||||
|
|
||||||
|
ap_list_reconfig(hapd_iface, oldconf);
|
||||||
|
|
||||||
|
hapd_iface->change->beacon_changed = beacon_changed;
|
||||||
|
|
||||||
|
hapd_iface->reload_iface_cb = NULL;
|
||||||
|
cb(hapd_iface, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reload_iface2_handler - Handler that calls reload_face2
|
||||||
|
* @eloop_data: Stores the struct hostapd_iface for the interface.
|
||||||
|
* @user_ctx: Unused.
|
||||||
|
*/
|
||||||
|
static void reload_iface2_handler(void *eloop_data, void *user_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *hapd_iface = eloop_data;
|
||||||
|
|
||||||
|
reload_iface2(hapd_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reload_hw_mode_done - Callback for after the HW mode is setup
|
||||||
|
* @hapd_iface: Pointer to interface data.
|
||||||
|
* @status: Status of the HW mode setup.
|
||||||
|
*/
|
||||||
|
static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||||
|
struct hostapd_config_change *change = hapd_iface->change;
|
||||||
|
struct hostapd_config *newconf = change->newconf;
|
||||||
|
hostapd_iface_cb cb;
|
||||||
|
int freq;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
printf("Failed to select hw_mode.\n");
|
||||||
|
|
||||||
|
cb = hapd_iface->reload_iface_cb;
|
||||||
|
hapd_iface->reload_iface_cb = NULL;
|
||||||
|
cb(hapd_iface, -1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
freq = hostapd_hw_get_freq(hapd, newconf->channel);
|
||||||
|
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d Frequency: %d MHz",
|
||||||
|
hostapd_hw_mode_txt(newconf->hw_mode),
|
||||||
|
newconf->channel, freq);
|
||||||
|
|
||||||
|
if (hostapd_set_freq(hapd, newconf->hw_mode, freq)) {
|
||||||
|
printf("Could not set channel %d (%d MHz) for kernel "
|
||||||
|
"driver\n", newconf->channel, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
change->beacon_changed++;
|
||||||
|
|
||||||
|
reload_iface2(hapd_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_config_reload_iface_start - Start interface reload
|
||||||
|
* @hapd_iface: Pointer to interface data.
|
||||||
|
* @cb: The function to callback when done.
|
||||||
|
* Returns: 0 if it starts successfully; cb will be called when done.
|
||||||
|
* -1 on failure; cb will not be called.
|
||||||
|
*/
|
||||||
|
static int hostapd_config_reload_iface_start(struct hostapd_iface *hapd_iface,
|
||||||
|
hostapd_iface_cb cb)
|
||||||
|
{
|
||||||
|
struct hostapd_config_change *change = hapd_iface->change;
|
||||||
|
struct hostapd_config *newconf = change->newconf;
|
||||||
|
struct hostapd_config *oldconf = change->oldconf;
|
||||||
|
struct hostapd_data *hapd = hapd_iface->bss[0];
|
||||||
|
|
||||||
|
if (hapd_iface->reload_iface_cb) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"%s: Interface reload already in progress.",
|
||||||
|
hapd_iface->bss[0]->conf->iface);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hapd_iface->reload_iface_cb = cb;
|
||||||
|
|
||||||
|
if (newconf->bridge_packets != oldconf->bridge_packets &&
|
||||||
|
hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
|
||||||
|
hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets))
|
||||||
|
printf("Failed to set bridge_packets for kernel driver\n");
|
||||||
|
|
||||||
|
if (newconf->channel != oldconf->channel ||
|
||||||
|
newconf->hw_mode != oldconf->hw_mode ||
|
||||||
|
rate_array_diff(newconf->supported_rates,
|
||||||
|
oldconf->supported_rates) ||
|
||||||
|
rate_array_diff(newconf->basic_rates, oldconf->basic_rates)) {
|
||||||
|
hostapd_free_stas(hapd);
|
||||||
|
|
||||||
|
if (hostapd_get_hw_features(hapd_iface)) {
|
||||||
|
printf("Could not read HW feature info from the kernel"
|
||||||
|
" driver.\n");
|
||||||
|
hapd_iface->reload_iface_cb = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hostapd_select_hw_mode_start(hapd_iface,
|
||||||
|
reload_hw_mode_done)) {
|
||||||
|
printf("Failed to start select hw_mode.\n");
|
||||||
|
hapd_iface->reload_iface_cb = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eloop_register_timeout(0, 0, reload_iface2_handler, hapd_iface, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hostapd_reconfig_bss(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_bss_config *newbss,
|
||||||
|
struct hostapd_bss_config *oldbss,
|
||||||
|
struct hostapd_config *oldconf,
|
||||||
|
int beacon_changed)
|
||||||
|
{
|
||||||
|
struct hostapd_config_change change;
|
||||||
|
int encr_changed = 0;
|
||||||
|
struct radius_client_data *old_radius;
|
||||||
|
|
||||||
|
radius_client_flush(hapd->radius, 0);
|
||||||
|
|
||||||
|
if (hostapd_set_dtim_period(hapd, newbss->dtim_period))
|
||||||
|
printf("Could not set DTIM period for kernel driver\n");
|
||||||
|
|
||||||
|
if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
|
||||||
|
os_memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
|
||||||
|
newbss->ssid.ssid_len) != 0) {
|
||||||
|
if (hostapd_set_ssid(hapd, (u8 *) newbss->ssid.ssid,
|
||||||
|
newbss->ssid.ssid_len))
|
||||||
|
printf("Could not set SSID for kernel driver\n");
|
||||||
|
beacon_changed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid)
|
||||||
|
beacon_changed++;
|
||||||
|
|
||||||
|
if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) {
|
||||||
|
encr_changed++;
|
||||||
|
beacon_changed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vlan_reconfig(hapd, oldconf, oldbss);
|
||||||
|
|
||||||
|
if (beacon_changed) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Updating beacon frame information");
|
||||||
|
ieee802_11_set_beacon(hapd);
|
||||||
|
}
|
||||||
|
|
||||||
|
change.hapd = hapd;
|
||||||
|
change.oldconf = oldconf;
|
||||||
|
change.newconf = hapd->iconf;
|
||||||
|
change.oldbss = oldbss;
|
||||||
|
change.newbss = newbss;
|
||||||
|
change.mac_acl_changed = hostapd_acl_diff(newbss, oldbss);
|
||||||
|
if (newbss->max_num_sta != oldbss->max_num_sta &&
|
||||||
|
newbss->max_num_sta < hapd->num_sta) {
|
||||||
|
change.num_sta_remove = hapd->num_sta - newbss->max_num_sta;
|
||||||
|
} else
|
||||||
|
change.num_sta_remove = 0;
|
||||||
|
ap_for_each_sta(hapd, hostapd_config_reload_sta, &change);
|
||||||
|
|
||||||
|
old_radius = hapd->radius;
|
||||||
|
hapd->radius = radius_client_reconfig(hapd->radius, hapd,
|
||||||
|
oldbss->radius, newbss->radius);
|
||||||
|
hapd->radius_client_reconfigured = old_radius != hapd->radius ||
|
||||||
|
hostapd_ip_diff(&newbss->own_ip_addr, &oldbss->own_ip_addr);
|
||||||
|
|
||||||
|
ieee802_1x_reconfig(hapd, oldconf, oldbss);
|
||||||
|
iapp_reconfig(hapd, oldconf, oldbss);
|
||||||
|
|
||||||
|
hostapd_acl_reconfig(hapd, oldconf);
|
||||||
|
accounting_reconfig(hapd, oldconf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* config_reload2 - Part 2 of configuration reloading
|
||||||
|
* @hapd_iface:
|
||||||
|
*/
|
||||||
|
static void config_reload2(struct hostapd_iface *hapd_iface, int status)
|
||||||
|
{
|
||||||
|
struct hostapd_config_change *change = hapd_iface->change;
|
||||||
|
struct hostapd_data *hapd = change->hapd;
|
||||||
|
struct hostapd_config *newconf = change->newconf;
|
||||||
|
struct hostapd_config *oldconf = change->oldconf;
|
||||||
|
int beacon_changed = change->beacon_changed;
|
||||||
|
struct hostapd_data **new_hapd = change->new_hapd;
|
||||||
|
struct hostapd_data **old_hapd = change->old_hapd;
|
||||||
|
int num_old_hapd = change->num_old_hapd;
|
||||||
|
size_t i, j, max_bss, same_bssid;
|
||||||
|
struct hostapd_bss_config *newbss, *oldbss;
|
||||||
|
u8 *prev_addr;
|
||||||
|
hostapd_iface_cb cb;
|
||||||
|
|
||||||
|
os_free(change);
|
||||||
|
hapd_iface->change = NULL;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
printf("Failed to setup new interface config\n");
|
||||||
|
|
||||||
|
cb = hapd_iface->config_reload_cb;
|
||||||
|
hapd_iface->config_reload_cb = NULL;
|
||||||
|
|
||||||
|
/* Invalid configuration - cleanup and terminate hostapd */
|
||||||
|
hapd_iface->bss = old_hapd;
|
||||||
|
hapd_iface->num_bss = num_old_hapd;
|
||||||
|
hapd_iface->conf = hapd->iconf = oldconf;
|
||||||
|
hapd->conf = &oldconf->bss[0];
|
||||||
|
hostapd_config_free(newconf);
|
||||||
|
os_free(new_hapd);
|
||||||
|
|
||||||
|
cb(hapd_iface, -2);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If any BSSes have been removed, added, or had their BSSIDs changed,
|
||||||
|
* completely remove and reinitialize such BSSes and all the BSSes
|
||||||
|
* following them since their BSSID might have changed.
|
||||||
|
*/
|
||||||
|
max_bss = oldconf->num_bss;
|
||||||
|
if (max_bss > newconf->num_bss)
|
||||||
|
max_bss = newconf->num_bss;
|
||||||
|
|
||||||
|
for (i = 0; i < max_bss; i++) {
|
||||||
|
if (os_strcmp(oldconf->bss[i].iface, newconf->bss[i].iface) !=
|
||||||
|
0 || hostapd_mac_comp(oldconf->bss[i].bssid,
|
||||||
|
newconf->bss[i].bssid) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
same_bssid = i;
|
||||||
|
|
||||||
|
for (i = 0; i < oldconf->num_bss; i++) {
|
||||||
|
oldbss = &oldconf->bss[i];
|
||||||
|
newbss = NULL;
|
||||||
|
for (j = 0; j < newconf->num_bss; j++) {
|
||||||
|
if (os_strcmp(oldbss->iface, newconf->bss[j].iface) ==
|
||||||
|
0) {
|
||||||
|
newbss = &newconf->bss[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newbss && i < same_bssid) {
|
||||||
|
hapd = hapd_iface->bss[j] = old_hapd[i];
|
||||||
|
hapd->iconf = newconf;
|
||||||
|
hapd->conf = newbss;
|
||||||
|
hostapd_reconfig_bss(hapd, newbss, oldbss, oldconf,
|
||||||
|
beacon_changed);
|
||||||
|
} else {
|
||||||
|
hapd = old_hapd[i];
|
||||||
|
wpa_printf(MSG_DEBUG, "Removing BSS (ifname %s)",
|
||||||
|
hapd->conf->iface);
|
||||||
|
hostapd_free_stas(hapd);
|
||||||
|
/* Send broadcast deauthentication for this BSS, but do
|
||||||
|
* not clear all STAs from the driver since other BSSes
|
||||||
|
* may have STA entries. The driver will remove all STA
|
||||||
|
* entries for this BSS anyway when the interface is
|
||||||
|
* being removed. */
|
||||||
|
#if 0
|
||||||
|
hostapd_deauth_all_stas(hapd);
|
||||||
|
hostapd_cleanup(hapd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
os_free(hapd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prev_addr = hapd_iface->bss[0]->own_addr;
|
||||||
|
hapd = hapd_iface->bss[0];
|
||||||
|
for (j = 0; j < newconf->num_bss; j++) {
|
||||||
|
if (hapd_iface->bss[j] != NULL) {
|
||||||
|
prev_addr = hapd_iface->bss[j]->own_addr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newbss = &newconf->bss[j];
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Reconfiguration: adding new BSS "
|
||||||
|
"(ifname=%s)", newbss->iface);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
hapd = hapd_iface->bss[j] =
|
||||||
|
hostapd_alloc_bss_data(hapd_iface, newconf, newbss);
|
||||||
|
if (hapd == NULL) {
|
||||||
|
printf("Failed to initialize new BSS\n");
|
||||||
|
/* FIX: This one is somewhat hard to recover
|
||||||
|
* from.. Would need to remove this BSS from
|
||||||
|
* conf and BSS list. */
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
hapd->driver = hapd_iface->bss[0]->driver;
|
||||||
|
hapd->iface = hapd_iface;
|
||||||
|
hapd->iconf = newconf;
|
||||||
|
hapd->conf = newbss;
|
||||||
|
|
||||||
|
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
|
||||||
|
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
|
||||||
|
prev_addr = hapd->own_addr;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (hostapd_setup_bss(hapd, j == 0)) {
|
||||||
|
printf("Failed to setup new BSS\n");
|
||||||
|
/* FIX */
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
os_free(old_hapd);
|
||||||
|
hostapd_config_free(oldconf);
|
||||||
|
|
||||||
|
cb = hapd_iface->config_reload_cb;
|
||||||
|
hapd_iface->config_reload_cb = NULL;
|
||||||
|
|
||||||
|
cb(hapd_iface, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_config_reload_start - Start reconfiguration of an interface
|
||||||
|
* @hapd_iface: Pointer to hostapd interface data
|
||||||
|
* @cb: Function to be called back when done.
|
||||||
|
* The status indicates:
|
||||||
|
* 0 = success, new configuration in use;
|
||||||
|
* -1 = failed to update configuraiton, old configuration in use;
|
||||||
|
* -2 = failed to update configuration and failed to recover; caller
|
||||||
|
* should cleanup and terminate hostapd
|
||||||
|
* Returns:
|
||||||
|
* 0 = reconfiguration started;
|
||||||
|
* -1 = failed to update configuration, old configuration in use;
|
||||||
|
* -2 = failed to update configuration and failed to recover; caller
|
||||||
|
* should cleanup and terminate hostapd
|
||||||
|
*/
|
||||||
|
int hostapd_config_reload_start(struct hostapd_iface *hapd_iface,
|
||||||
|
hostapd_iface_cb cb)
|
||||||
|
{
|
||||||
|
struct hostapd_config *newconf, *oldconf;
|
||||||
|
struct hostapd_config_change *change;
|
||||||
|
struct hostapd_data *hapd = NULL;
|
||||||
|
struct hostapd_data **old_hapd, **new_hapd;
|
||||||
|
int num_old_hapd;
|
||||||
|
|
||||||
|
if (hapd_iface->config_reload_cb) {
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: Config reload already in progress.",
|
||||||
|
hapd_iface->bss[0]->conf->iface);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
newconf = hostapd_config_read(hapd_iface->config_fname);
|
||||||
|
if (newconf == NULL) {
|
||||||
|
printf("Failed to read new configuration file - continuing "
|
||||||
|
"with old.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (os_strcmp(newconf->bss[0].iface, hapd_iface->conf->bss[0].iface) !=
|
||||||
|
0) {
|
||||||
|
printf("Interface name changing is not allowed in "
|
||||||
|
"configuration reloading (%s -> %s).\n",
|
||||||
|
hapd_iface->conf->bss[0].iface, newconf->bss[0].iface);
|
||||||
|
hostapd_config_free(newconf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_hapd = os_zalloc(newconf->num_bss *
|
||||||
|
sizeof(struct hostapd_data *));
|
||||||
|
if (new_hapd == NULL) {
|
||||||
|
hostapd_config_free(newconf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
old_hapd = hapd_iface->bss;
|
||||||
|
num_old_hapd = hapd_iface->num_bss;
|
||||||
|
|
||||||
|
hapd_iface->bss = new_hapd;
|
||||||
|
hapd_iface->num_bss = newconf->num_bss;
|
||||||
|
/*
|
||||||
|
* First BSS remains the same since interface name changing was
|
||||||
|
* prohibited above. Now, this is only used in
|
||||||
|
* hostapd_config_reload_iface() and following loop will anyway set
|
||||||
|
* this again.
|
||||||
|
*/
|
||||||
|
hapd = hapd_iface->bss[0] = old_hapd[0];
|
||||||
|
|
||||||
|
oldconf = hapd_iface->conf;
|
||||||
|
hapd->iconf = hapd_iface->conf = newconf;
|
||||||
|
hapd->conf = &newconf->bss[0];
|
||||||
|
|
||||||
|
change = os_zalloc(sizeof(struct hostapd_config_change));
|
||||||
|
if (change == NULL) {
|
||||||
|
hostapd_config_free(newconf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
change->hapd = hapd;
|
||||||
|
change->newconf = newconf;
|
||||||
|
change->oldconf = oldconf;
|
||||||
|
change->beacon_changed = 0;
|
||||||
|
change->hapd_iface = hapd_iface;
|
||||||
|
change->new_hapd = new_hapd;
|
||||||
|
change->old_hapd = old_hapd;
|
||||||
|
change->num_old_hapd = num_old_hapd;
|
||||||
|
|
||||||
|
hapd_iface->config_reload_cb = cb;
|
||||||
|
hapd_iface->change = change;
|
||||||
|
if (hostapd_config_reload_iface_start(hapd_iface, config_reload2)) {
|
||||||
|
printf("Failed to start setup of new interface config\n");
|
||||||
|
|
||||||
|
hapd_iface->config_reload_cb = NULL;
|
||||||
|
os_free(change);
|
||||||
|
hapd_iface->change = NULL;
|
||||||
|
|
||||||
|
/* Invalid configuration - cleanup and terminate hostapd */
|
||||||
|
hapd_iface->bss = old_hapd;
|
||||||
|
hapd_iface->num_bss = num_old_hapd;
|
||||||
|
hapd_iface->conf = hapd->iconf = oldconf;
|
||||||
|
hapd->conf = &oldconf->bss[0];
|
||||||
|
hostapd_config_free(newconf);
|
||||||
|
os_free(new_hapd);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
580
hostapd/sta_info.c
Normal file
580
hostapd/sta_info.c
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Station table
|
||||||
|
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "sta_info.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
#include "accounting.h"
|
||||||
|
#include "ieee802_1x.h"
|
||||||
|
#include "ieee802_11.h"
|
||||||
|
#include "radius/radius.h"
|
||||||
|
#include "wpa.h"
|
||||||
|
#include "preauth.h"
|
||||||
|
#include "radius/radius_client.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
#include "hw_features.h"
|
||||||
|
#include "mlme.h"
|
||||||
|
#include "vlan_init.h"
|
||||||
|
|
||||||
|
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u32 flags);
|
||||||
|
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
|
||||||
|
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||||
|
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
void *ctx),
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||||
|
if (cb(hapd, sta, ctx))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
|
||||||
|
{
|
||||||
|
struct sta_info *s;
|
||||||
|
|
||||||
|
s = hapd->sta_hash[STA_HASH(sta)];
|
||||||
|
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
|
||||||
|
s = s->hnext;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
struct sta_info *tmp;
|
||||||
|
|
||||||
|
if (hapd->sta_list == sta) {
|
||||||
|
hapd->sta_list = sta->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = hapd->sta_list;
|
||||||
|
while (tmp != NULL && tmp->next != sta)
|
||||||
|
tmp = tmp->next;
|
||||||
|
if (tmp == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
|
||||||
|
"list.", MAC2STR(sta->addr));
|
||||||
|
} else
|
||||||
|
tmp->next = sta->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
|
||||||
|
hapd->sta_hash[STA_HASH(sta->addr)] = sta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
struct sta_info *s;
|
||||||
|
|
||||||
|
s = hapd->sta_hash[STA_HASH(sta->addr)];
|
||||||
|
if (s == NULL) return;
|
||||||
|
if (os_memcmp(s->addr, sta->addr, 6) == 0) {
|
||||||
|
hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (s->hnext != NULL &&
|
||||||
|
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
|
||||||
|
s = s->hnext;
|
||||||
|
if (s->hnext != NULL)
|
||||||
|
s->hnext = s->hnext->hnext;
|
||||||
|
else
|
||||||
|
wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
|
||||||
|
" from hash table", MAC2STR(sta->addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
int set_beacon = 0;
|
||||||
|
|
||||||
|
accounting_sta_stop(hapd, sta);
|
||||||
|
|
||||||
|
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
|
||||||
|
!(sta->flags & WLAN_STA_PREAUTH))
|
||||||
|
hostapd_sta_remove(hapd, sta->addr);
|
||||||
|
|
||||||
|
ap_sta_hash_del(hapd, sta);
|
||||||
|
ap_sta_list_del(hapd, sta);
|
||||||
|
|
||||||
|
if (sta->aid > 0)
|
||||||
|
hapd->sta_aid[sta->aid - 1] = NULL;
|
||||||
|
|
||||||
|
hapd->num_sta--;
|
||||||
|
if (sta->nonerp_set) {
|
||||||
|
sta->nonerp_set = 0;
|
||||||
|
hapd->iface->num_sta_non_erp--;
|
||||||
|
if (hapd->iface->num_sta_non_erp == 0)
|
||||||
|
set_beacon++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta->no_short_slot_time_set) {
|
||||||
|
sta->no_short_slot_time_set = 0;
|
||||||
|
hapd->iface->num_sta_no_short_slot_time--;
|
||||||
|
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||||
|
&& hapd->iface->num_sta_no_short_slot_time == 0)
|
||||||
|
set_beacon++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta->no_short_preamble_set) {
|
||||||
|
sta->no_short_preamble_set = 0;
|
||||||
|
hapd->iface->num_sta_no_short_preamble--;
|
||||||
|
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
|
||||||
|
&& hapd->iface->num_sta_no_short_preamble == 0)
|
||||||
|
set_beacon++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_beacon)
|
||||||
|
ieee802_11_set_beacons(hapd->iface);
|
||||||
|
|
||||||
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||||
|
|
||||||
|
ieee802_1x_free_station(sta);
|
||||||
|
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||||
|
rsn_preauth_free_station(hapd, sta);
|
||||||
|
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||||
|
|
||||||
|
os_free(sta->last_assoc_req);
|
||||||
|
os_free(sta->challenge);
|
||||||
|
os_free(sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_free_stas(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct sta_info *sta, *prev;
|
||||||
|
|
||||||
|
sta = hapd->sta_list;
|
||||||
|
|
||||||
|
while (sta) {
|
||||||
|
prev = sta;
|
||||||
|
if (sta->flags & WLAN_STA_AUTH) {
|
||||||
|
mlme_deauthenticate_indication(
|
||||||
|
hapd, sta, WLAN_REASON_UNSPECIFIED);
|
||||||
|
}
|
||||||
|
sta = sta->next;
|
||||||
|
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
|
||||||
|
MAC2STR(prev->addr));
|
||||||
|
ap_free_sta(hapd, prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
unsigned long next_time = 0;
|
||||||
|
|
||||||
|
if (sta->timeout_next == STA_REMOVE) {
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||||
|
"local deauth request");
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||||
|
(sta->timeout_next == STA_NULLFUNC ||
|
||||||
|
sta->timeout_next == STA_DISASSOC)) {
|
||||||
|
int inactive_sec;
|
||||||
|
wpa_printf(MSG_DEBUG, "Checking STA " MACSTR " inactivity:",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
inactive_sec = hostapd_get_inact_sec(hapd, sta->addr);
|
||||||
|
if (inactive_sec == -1) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not get station info "
|
||||||
|
"from kernel driver for " MACSTR ".",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
|
||||||
|
sta->flags & WLAN_STA_ASSOC) {
|
||||||
|
/* station activity detected; reset timeout state */
|
||||||
|
wpa_printf(MSG_DEBUG, " Station has been active");
|
||||||
|
sta->timeout_next = STA_NULLFUNC;
|
||||||
|
next_time = hapd->conf->ap_max_inactivity -
|
||||||
|
inactive_sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||||
|
sta->timeout_next == STA_DISASSOC &&
|
||||||
|
!(sta->flags & WLAN_STA_PENDING_POLL)) {
|
||||||
|
wpa_printf(MSG_DEBUG, " Station has ACKed data poll");
|
||||||
|
/* data nullfunc frame poll did not produce TX errors; assume
|
||||||
|
* station ACKed it */
|
||||||
|
sta->timeout_next = STA_NULLFUNC;
|
||||||
|
next_time = hapd->conf->ap_max_inactivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_time) {
|
||||||
|
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
|
||||||
|
sta);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta->timeout_next == STA_NULLFUNC &&
|
||||||
|
(sta->flags & WLAN_STA_ASSOC)) {
|
||||||
|
/* send data frame to poll STA and check whether this frame
|
||||||
|
* is ACKed */
|
||||||
|
struct ieee80211_hdr hdr;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, " Polling STA with data frame");
|
||||||
|
sta->flags |= WLAN_STA_PENDING_POLL;
|
||||||
|
|
||||||
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
|
/* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
|
||||||
|
* it is apparently not retried so TX Exc events are not
|
||||||
|
* received for it */
|
||||||
|
os_memset(&hdr, 0, sizeof(hdr));
|
||||||
|
hdr.frame_control =
|
||||||
|
IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
|
||||||
|
hdr.frame_control |= host_to_le16(BIT(1));
|
||||||
|
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
|
||||||
|
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
|
||||||
|
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
|
||||||
|
ETH_ALEN);
|
||||||
|
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
|
||||||
|
perror("ap_handle_timer: send");
|
||||||
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||||
|
} else if (sta->timeout_next != STA_REMOVE) {
|
||||||
|
int deauth = sta->timeout_next == STA_DEAUTH;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
|
||||||
|
deauth ? "deauthentication" : "disassociation",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
|
||||||
|
if (deauth) {
|
||||||
|
hostapd_sta_deauth(hapd, sta->addr,
|
||||||
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||||
|
} else {
|
||||||
|
hostapd_sta_disassoc(
|
||||||
|
hapd, sta->addr,
|
||||||
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sta->timeout_next) {
|
||||||
|
case STA_NULLFUNC:
|
||||||
|
sta->timeout_next = STA_DISASSOC;
|
||||||
|
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
|
||||||
|
hapd, sta);
|
||||||
|
break;
|
||||||
|
case STA_DISASSOC:
|
||||||
|
sta->flags &= ~WLAN_STA_ASSOC;
|
||||||
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||||
|
if (!sta->acct_terminate_cause)
|
||||||
|
sta->acct_terminate_cause =
|
||||||
|
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
||||||
|
accounting_sta_stop(hapd, sta);
|
||||||
|
ieee802_1x_free_station(sta);
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "disassociated due to "
|
||||||
|
"inactivity");
|
||||||
|
sta->timeout_next = STA_DEAUTH;
|
||||||
|
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
|
||||||
|
hapd, sta);
|
||||||
|
mlme_disassociate_indication(
|
||||||
|
hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
|
||||||
|
break;
|
||||||
|
case STA_DEAUTH:
|
||||||
|
case STA_REMOVE:
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||||
|
"inactivity");
|
||||||
|
if (!sta->acct_terminate_cause)
|
||||||
|
sta->acct_terminate_cause =
|
||||||
|
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
||||||
|
mlme_deauthenticate_indication(
|
||||||
|
hapd, sta,
|
||||||
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
struct sta_info *sta = timeout_ctx;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
if (!(sta->flags & WLAN_STA_AUTH))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mlme_deauthenticate_indication(hapd, sta,
|
||||||
|
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
|
||||||
|
"session timeout");
|
||||||
|
sta->acct_terminate_cause =
|
||||||
|
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
|
||||||
|
os_memcpy(addr, sta->addr, ETH_ALEN);
|
||||||
|
ap_free_sta(hapd, sta);
|
||||||
|
hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u32 session_timeout)
|
||||||
|
{
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
|
||||||
|
"seconds", session_timeout);
|
||||||
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||||
|
eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
|
||||||
|
hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, addr);
|
||||||
|
if (sta)
|
||||||
|
return sta;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, " New STA");
|
||||||
|
if (hapd->num_sta >= hapd->conf->max_num_sta) {
|
||||||
|
/* FIX: might try to remove some old STAs first? */
|
||||||
|
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
|
||||||
|
hapd->num_sta, hapd->conf->max_num_sta);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta = os_zalloc(sizeof(struct sta_info));
|
||||||
|
if (sta == NULL) {
|
||||||
|
wpa_printf(MSG_ERROR, "malloc failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
|
||||||
|
|
||||||
|
/* initialize STA info data */
|
||||||
|
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
||||||
|
ap_handle_timer, hapd, sta);
|
||||||
|
os_memcpy(sta->addr, addr, ETH_ALEN);
|
||||||
|
sta->next = hapd->sta_list;
|
||||||
|
hapd->sta_list = sta;
|
||||||
|
hapd->num_sta++;
|
||||||
|
ap_sta_hash_add(hapd, sta);
|
||||||
|
sta->ssid = &hapd->conf->ssid;
|
||||||
|
|
||||||
|
return sta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
|
{
|
||||||
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
if (hostapd_sta_remove(hapd, sta->addr) &&
|
||||||
|
sta->flags & WLAN_STA_ASSOC) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
|
||||||
|
" from kernel driver.", MAC2STR(sta->addr));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ap_sta_in_other_bss(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta, u32 flags)
|
||||||
|
{
|
||||||
|
struct hostapd_iface *iface = hapd->iface;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < iface->num_bss; i++) {
|
||||||
|
struct hostapd_data *bss = iface->bss[i];
|
||||||
|
struct sta_info *sta2;
|
||||||
|
/* bss should always be set during operation, but it may be
|
||||||
|
* NULL during reconfiguration. Assume the STA is not
|
||||||
|
* associated to another BSS in that case to avoid NULL pointer
|
||||||
|
* dereferences. */
|
||||||
|
if (bss == hapd || bss == NULL)
|
||||||
|
continue;
|
||||||
|
sta2 = ap_get_sta(bss, sta->addr);
|
||||||
|
if (sta2 && ((sta2->flags & flags) == flags))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u16 reason)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
|
||||||
|
hapd->conf->iface, MAC2STR(sta->addr));
|
||||||
|
sta->flags &= ~WLAN_STA_ASSOC;
|
||||||
|
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
|
||||||
|
ap_sta_remove(hapd, sta);
|
||||||
|
sta->timeout_next = STA_DEAUTH;
|
||||||
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
||||||
|
ap_handle_timer, hapd, sta);
|
||||||
|
accounting_sta_stop(hapd, sta);
|
||||||
|
ieee802_1x_free_station(sta);
|
||||||
|
|
||||||
|
mlme_disassociate_indication(hapd, sta, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u16 reason)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
|
||||||
|
hapd->conf->iface, MAC2STR(sta->addr));
|
||||||
|
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||||
|
if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
|
||||||
|
ap_sta_remove(hapd, sta);
|
||||||
|
sta->timeout_next = STA_REMOVE;
|
||||||
|
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||||
|
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||||
|
ap_handle_timer, hapd, sta);
|
||||||
|
accounting_sta_stop(hapd, sta);
|
||||||
|
ieee802_1x_free_station(sta);
|
||||||
|
|
||||||
|
mlme_deauthenticate_indication(hapd, sta, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int old_vlanid)
|
||||||
|
{
|
||||||
|
const char *iface;
|
||||||
|
struct hostapd_vlan *vlan = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not proceed furthur if the vlan id remains same. We do not want
|
||||||
|
* duplicate dynamic vlan entries.
|
||||||
|
*/
|
||||||
|
if (sta->vlan_id == old_vlanid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During 1x reauth, if the vlan id changes, then remove the old id and
|
||||||
|
* proceed furthur to add the new one.
|
||||||
|
*/
|
||||||
|
if (old_vlanid > 0)
|
||||||
|
vlan_remove_dynamic(hapd, old_vlanid);
|
||||||
|
|
||||||
|
iface = hapd->conf->iface;
|
||||||
|
if (sta->ssid->vlan[0])
|
||||||
|
iface = sta->ssid->vlan;
|
||||||
|
|
||||||
|
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||||
|
sta->vlan_id = 0;
|
||||||
|
else if (sta->vlan_id > 0) {
|
||||||
|
vlan = hapd->conf->vlan;
|
||||||
|
while (vlan) {
|
||||||
|
if (vlan->vlan_id == sta->vlan_id ||
|
||||||
|
vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||||
|
iface = vlan->ifname;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vlan = vlan->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sta->vlan_id > 0 && vlan == NULL) {
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
|
||||||
|
"binding station to (vlan_id=%d)",
|
||||||
|
sta->vlan_id);
|
||||||
|
return -1;
|
||||||
|
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||||
|
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
|
||||||
|
if (vlan == NULL) {
|
||||||
|
hostapd_logger(hapd, sta->addr,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "could not add "
|
||||||
|
"dynamic VLAN interface for vlan_id=%d",
|
||||||
|
sta->vlan_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface = vlan->ifname;
|
||||||
|
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||||
|
hostapd_logger(hapd, sta->addr,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||||
|
"configure encryption for dynamic VLAN "
|
||||||
|
"interface for vlan_id=%d",
|
||||||
|
sta->vlan_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
|
||||||
|
"interface '%s'", iface);
|
||||||
|
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
|
||||||
|
if (sta->vlan_id > 0) {
|
||||||
|
vlan->dynamic_vlan++;
|
||||||
|
hostapd_logger(hapd, sta->addr,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "updated existing "
|
||||||
|
"dynamic VLAN interface '%s'", iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update encryption configuration for statically generated
|
||||||
|
* VLAN interface. This is only used for static WEP
|
||||||
|
* configuration for the case where hostapd did not yet know
|
||||||
|
* which keys are to be used when the interface was added.
|
||||||
|
*/
|
||||||
|
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
|
||||||
|
hostapd_logger(hapd, sta->addr,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||||
|
"configure encryption for VLAN "
|
||||||
|
"interface for vlan_id=%d",
|
||||||
|
sta->vlan_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
|
||||||
|
"'%s'", iface);
|
||||||
|
|
||||||
|
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
|
||||||
|
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
|
||||||
|
|
||||||
|
return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
|
||||||
|
}
|
40
hostapd/sta_info.h
Normal file
40
hostapd/sta_info.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* hostapd / Station table
|
||||||
|
* Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STA_INFO_H
|
||||||
|
#define STA_INFO_H
|
||||||
|
|
||||||
|
int ap_for_each_sta(struct hostapd_data *hapd,
|
||||||
|
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
void *ctx),
|
||||||
|
void *ctx);
|
||||||
|
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||||
|
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
|
void hostapd_free_stas(struct hostapd_data *hapd);
|
||||||
|
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u32 session_timeout);
|
||||||
|
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
|
||||||
|
struct sta_info *sta);
|
||||||
|
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
|
||||||
|
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u16 reason);
|
||||||
|
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
u16 reason);
|
||||||
|
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
int old_vlanid);
|
||||||
|
|
||||||
|
#endif /* STA_INFO_H */
|
832
hostapd/vlan_init.c
Normal file
832
hostapd/vlan_init.c
Normal file
|
@ -0,0 +1,832 @@
|
||||||
|
/*
|
||||||
|
* hostapd / VLAN initialization
|
||||||
|
* Copyright 2003, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "hostapd.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "vlan_init.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/sockios.h>
|
||||||
|
#include <linux/if_vlan.h>
|
||||||
|
typedef __uint64_t __u64;
|
||||||
|
typedef __uint32_t __u32;
|
||||||
|
typedef __int32_t __s32;
|
||||||
|
typedef __uint16_t __u16;
|
||||||
|
typedef __int16_t __s16;
|
||||||
|
typedef __uint8_t __u8;
|
||||||
|
#include <linux/if_bridge.h>
|
||||||
|
|
||||||
|
#include "priv_netlink.h"
|
||||||
|
#include "eloop.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct full_dynamic_vlan {
|
||||||
|
int s; /* socket on which to listen for new/removed interfaces. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int ifconfig_helper(const char *if_name, int up)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&ifr, 0, sizeof(ifr));
|
||||||
|
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
|
||||||
|
perror("ioctl[SIOCGIFFLAGS]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (up)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
|
||||||
|
perror("ioctl[SIOCSIFFLAGS]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ifconfig_up(const char *if_name)
|
||||||
|
{
|
||||||
|
return ifconfig_helper(if_name, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ifconfig_down(const char *if_name)
|
||||||
|
{
|
||||||
|
return ifconfig_helper(if_name, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are only available in recent linux headers (without the leading
|
||||||
|
* underscore).
|
||||||
|
*/
|
||||||
|
#define _GET_VLAN_REALDEV_NAME_CMD 8
|
||||||
|
#define _GET_VLAN_VID_CMD 9
|
||||||
|
|
||||||
|
/* This value should be 256 ONLY. If it is something else, then hostapd
|
||||||
|
* might crash!, as this value has been hard-coded in 2.4.x kernel
|
||||||
|
* bridging code.
|
||||||
|
*/
|
||||||
|
#define MAX_BR_PORTS 256
|
||||||
|
|
||||||
|
static int br_delif(const char *br_name, const char *if_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct ifreq ifr;
|
||||||
|
unsigned long args[2];
|
||||||
|
int if_index;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if_index = if_nametoindex(if_name);
|
||||||
|
|
||||||
|
if (if_index == 0) {
|
||||||
|
printf("Failure determining interface index for '%s'\n",
|
||||||
|
if_name);
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[0] = BRCTL_DEL_IF;
|
||||||
|
args[1] = if_index;
|
||||||
|
|
||||||
|
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||||
|
ifr.ifr_data = (__caddr_t) args;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
|
||||||
|
/* No error if interface already removed. */
|
||||||
|
perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add interface 'if_name' to the bridge 'br_name'
|
||||||
|
|
||||||
|
returns -1 on error
|
||||||
|
returns 1 if the interface is already part of the bridge
|
||||||
|
returns 0 otherwise
|
||||||
|
*/
|
||||||
|
static int br_addif(const char *br_name, const char *if_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct ifreq ifr;
|
||||||
|
unsigned long args[2];
|
||||||
|
int if_index;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if_index = if_nametoindex(if_name);
|
||||||
|
|
||||||
|
if (if_index == 0) {
|
||||||
|
printf("Failure determining interface index for '%s'\n",
|
||||||
|
if_name);
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
args[0] = BRCTL_ADD_IF;
|
||||||
|
args[1] = if_index;
|
||||||
|
|
||||||
|
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||||
|
ifr.ifr_data = (__caddr_t) args;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||||
|
if (errno == EBUSY) {
|
||||||
|
/* The interface is already added. */
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int br_delbr(const char *br_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long arg[2];
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg[0] = BRCTL_DEL_BRIDGE;
|
||||||
|
arg[1] = (unsigned long) br_name;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
|
||||||
|
/* No error if bridge already removed. */
|
||||||
|
perror("ioctl[BRCTL_DEL_BRIDGE]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add a bridge with the name 'br_name'.
|
||||||
|
|
||||||
|
returns -1 on error
|
||||||
|
returns 1 if the bridge already exists
|
||||||
|
returns 0 otherwise
|
||||||
|
*/
|
||||||
|
static int br_addbr(const char *br_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long arg[2];
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg[0] = BRCTL_ADD_BRIDGE;
|
||||||
|
arg[1] = (unsigned long) br_name;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
|
||||||
|
if (errno == EEXIST) {
|
||||||
|
/* The bridge is already added. */
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
perror("ioctl[BRCTL_ADD_BRIDGE]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int br_getnumports(const char *br_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
int port_cnt = 0;
|
||||||
|
unsigned long arg[4];
|
||||||
|
int ifindices[MAX_BR_PORTS];
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg[0] = BRCTL_GET_PORT_LIST;
|
||||||
|
arg[1] = (unsigned long) ifindices;
|
||||||
|
arg[2] = MAX_BR_PORTS;
|
||||||
|
arg[3] = 0;
|
||||||
|
|
||||||
|
os_memset(ifindices, 0, sizeof(ifindices));
|
||||||
|
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||||
|
ifr.ifr_data = (__caddr_t) arg;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||||
|
perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i < MAX_BR_PORTS; i++) {
|
||||||
|
if (ifindices[i] > 0) {
|
||||||
|
port_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return port_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int vlan_rem(const char *if_name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct vlan_ioctl_args if_request;
|
||||||
|
|
||||||
|
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||||
|
fprintf(stderr, "Interface name to long.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&if_request, 0, sizeof(if_request));
|
||||||
|
|
||||||
|
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||||
|
if_request.cmd = DEL_VLAN_CMD;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||||
|
perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add a vlan interface with VLAN ID 'vid' and tagged interface
|
||||||
|
'if_name'.
|
||||||
|
|
||||||
|
returns -1 on error
|
||||||
|
returns 1 if the interface already exists
|
||||||
|
returns 0 otherwise
|
||||||
|
*/
|
||||||
|
static int vlan_add(const char *if_name, int vid)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct vlan_ioctl_args if_request;
|
||||||
|
|
||||||
|
ifconfig_up(if_name);
|
||||||
|
|
||||||
|
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||||
|
fprintf(stderr, "Interface name to long.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&if_request, 0, sizeof(if_request));
|
||||||
|
|
||||||
|
/* Determine if a suitable vlan device already exists. */
|
||||||
|
|
||||||
|
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
|
||||||
|
vid);
|
||||||
|
|
||||||
|
if_request.cmd = _GET_VLAN_VID_CMD;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
|
||||||
|
|
||||||
|
if (if_request.u.VID == vid) {
|
||||||
|
if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
|
||||||
|
os_strncmp(if_request.u.device2, if_name,
|
||||||
|
sizeof(if_request.u.device2)) == 0) {
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A suitable vlan device does not already exist, add one. */
|
||||||
|
|
||||||
|
os_memset(&if_request, 0, sizeof(if_request));
|
||||||
|
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||||
|
if_request.u.VID = vid;
|
||||||
|
if_request.cmd = ADD_VLAN_CMD;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||||
|
perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int vlan_set_name_type(unsigned int name_type)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct vlan_ioctl_args if_request;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("socket[AF_INET,SOCK_STREAM]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&if_request, 0, sizeof(if_request));
|
||||||
|
|
||||||
|
if_request.u.name_type = name_type;
|
||||||
|
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
|
||||||
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||||
|
perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
char vlan_ifname[IFNAMSIZ];
|
||||||
|
char br_name[IFNAMSIZ];
|
||||||
|
struct hostapd_vlan *vlan = hapd->conf->vlan;
|
||||||
|
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||||
|
|
||||||
|
while (vlan) {
|
||||||
|
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||||
|
|
||||||
|
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
|
||||||
|
vlan->vlan_id);
|
||||||
|
|
||||||
|
if (!br_addbr(br_name))
|
||||||
|
vlan->clean |= DVLAN_CLEAN_BR;
|
||||||
|
|
||||||
|
ifconfig_up(br_name);
|
||||||
|
|
||||||
|
if (tagged_interface) {
|
||||||
|
|
||||||
|
if (!vlan_add(tagged_interface, vlan->vlan_id))
|
||||||
|
vlan->clean |= DVLAN_CLEAN_VLAN;
|
||||||
|
|
||||||
|
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
|
||||||
|
"vlan%d", vlan->vlan_id);
|
||||||
|
|
||||||
|
if (!br_addif(br_name, vlan_ifname))
|
||||||
|
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
|
||||||
|
|
||||||
|
ifconfig_up(vlan_ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!br_addif(br_name, ifname))
|
||||||
|
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
|
||||||
|
|
||||||
|
ifconfig_up(ifname);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vlan = vlan->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
char vlan_ifname[IFNAMSIZ];
|
||||||
|
char br_name[IFNAMSIZ];
|
||||||
|
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
|
||||||
|
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||||
|
int numports;
|
||||||
|
|
||||||
|
first = prev = vlan;
|
||||||
|
|
||||||
|
while (vlan) {
|
||||||
|
if (os_strcmp(ifname, vlan->ifname) == 0) {
|
||||||
|
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
|
||||||
|
vlan->vlan_id);
|
||||||
|
|
||||||
|
if (tagged_interface) {
|
||||||
|
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
|
||||||
|
"vlan%d", vlan->vlan_id);
|
||||||
|
|
||||||
|
numports = br_getnumports(br_name);
|
||||||
|
if (numports == 1) {
|
||||||
|
br_delif(br_name, vlan_ifname);
|
||||||
|
|
||||||
|
vlan_rem(vlan_ifname);
|
||||||
|
|
||||||
|
ifconfig_down(br_name);
|
||||||
|
br_delbr(br_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlan == first) {
|
||||||
|
hapd->conf->vlan = vlan->next;
|
||||||
|
} else {
|
||||||
|
prev->next = vlan->next;
|
||||||
|
}
|
||||||
|
os_free(vlan);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = vlan;
|
||||||
|
vlan = vlan->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
|
||||||
|
struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct ifinfomsg *ifi;
|
||||||
|
int attrlen, nlmsg_len, rta_len;
|
||||||
|
struct rtattr *attr;
|
||||||
|
|
||||||
|
if (len < sizeof(*ifi))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ifi = NLMSG_DATA(h);
|
||||||
|
|
||||||
|
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
|
||||||
|
|
||||||
|
attrlen = h->nlmsg_len - nlmsg_len;
|
||||||
|
if (attrlen < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
|
||||||
|
|
||||||
|
rta_len = RTA_ALIGN(sizeof(struct rtattr));
|
||||||
|
while (RTA_OK(attr, attrlen)) {
|
||||||
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
|
||||||
|
if (attr->rta_type == IFLA_IFNAME) {
|
||||||
|
int n = attr->rta_len - rta_len;
|
||||||
|
if (n < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
os_memset(ifname, 0, sizeof(ifname));
|
||||||
|
|
||||||
|
if ((size_t) n > sizeof(ifname))
|
||||||
|
n = sizeof(ifname);
|
||||||
|
os_memcpy(ifname, ((char *) attr) + rta_len, n);
|
||||||
|
|
||||||
|
if (del)
|
||||||
|
vlan_dellink(ifname, hapd);
|
||||||
|
else
|
||||||
|
vlan_newlink(ifname, hapd);
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = RTA_NEXT(attr, attrlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||||
|
{
|
||||||
|
char buf[8192];
|
||||||
|
int left;
|
||||||
|
struct sockaddr_nl from;
|
||||||
|
socklen_t fromlen;
|
||||||
|
struct nlmsghdr *h;
|
||||||
|
struct hostapd_data *hapd = eloop_ctx;
|
||||||
|
|
||||||
|
fromlen = sizeof(from);
|
||||||
|
left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
|
||||||
|
(struct sockaddr *) &from, &fromlen);
|
||||||
|
if (left < 0) {
|
||||||
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
|
perror("recvfrom(netlink)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = (struct nlmsghdr *) buf;
|
||||||
|
while (left >= (int) sizeof(*h)) {
|
||||||
|
int len, plen;
|
||||||
|
|
||||||
|
len = h->nlmsg_len;
|
||||||
|
plen = len - sizeof(*h);
|
||||||
|
if (len > left || plen < 0) {
|
||||||
|
printf("Malformed netlink message: "
|
||||||
|
"len=%d left=%d plen=%d", len, left, plen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (h->nlmsg_type) {
|
||||||
|
case RTM_NEWLINK:
|
||||||
|
vlan_read_ifnames(h, plen, 0, hapd);
|
||||||
|
break;
|
||||||
|
case RTM_DELLINK:
|
||||||
|
vlan_read_ifnames(h, plen, 1, hapd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = NLMSG_ALIGN(len);
|
||||||
|
left -= len;
|
||||||
|
h = (struct nlmsghdr *) ((char *) h + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left > 0) {
|
||||||
|
printf("%d extra bytes in the end of netlink message",
|
||||||
|
left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct full_dynamic_vlan *
|
||||||
|
full_dynamic_vlan_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
struct sockaddr_nl local;
|
||||||
|
struct full_dynamic_vlan *priv;
|
||||||
|
|
||||||
|
priv = os_zalloc(sizeof(*priv));
|
||||||
|
if (priv == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
|
||||||
|
|
||||||
|
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
|
if (priv->s < 0) {
|
||||||
|
perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
|
||||||
|
os_free(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
os_memset(&local, 0, sizeof(local));
|
||||||
|
local.nl_family = AF_NETLINK;
|
||||||
|
local.nl_groups = RTMGRP_LINK;
|
||||||
|
if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||||
|
perror("bind(netlink)");
|
||||||
|
close(priv->s);
|
||||||
|
os_free(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
|
||||||
|
{
|
||||||
|
close(priv->s);
|
||||||
|
os_free(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
|
||||||
|
{
|
||||||
|
if (priv == NULL)
|
||||||
|
return;
|
||||||
|
eloop_unregister_read_sock(priv->s);
|
||||||
|
close(priv->s);
|
||||||
|
os_free(priv);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
|
||||||
|
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_ssid *mssid, const char *dyn_vlan)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (dyn_vlan == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
|
||||||
|
* functions for setting up dynamic broadcast keys. */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (mssid->wep.key[i] &&
|
||||||
|
hostapd_set_encryption(dyn_vlan, hapd, "WEP", NULL,
|
||||||
|
i, mssid->wep.key[i],
|
||||||
|
mssid->wep.len[i],
|
||||||
|
i == mssid->wep.idx)) {
|
||||||
|
printf("VLAN: Could not set WEP encryption for "
|
||||||
|
"dynamic VLAN.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int vlan_dynamic_add(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_vlan *vlan)
|
||||||
|
{
|
||||||
|
while (vlan) {
|
||||||
|
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
||||||
|
hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
|
||||||
|
{
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
printf("Could not add VLAN iface: %s: %s\n",
|
||||||
|
vlan->ifname, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vlan = vlan->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vlan_dynamic_remove(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_vlan *vlan)
|
||||||
|
{
|
||||||
|
struct hostapd_vlan *next;
|
||||||
|
|
||||||
|
while (vlan) {
|
||||||
|
next = vlan->next;
|
||||||
|
|
||||||
|
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
|
||||||
|
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
|
||||||
|
NULL)) {
|
||||||
|
printf("Could not remove VLAN iface: %s: %s\n",
|
||||||
|
vlan->ifname, strerror(errno));
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
if (vlan->clean)
|
||||||
|
vlan_dellink(vlan->ifname, hapd);
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
vlan = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vlan_init(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vlan_deinit(struct hostapd_data *hapd)
|
||||||
|
{
|
||||||
|
vlan_dynamic_remove(hapd, hapd->conf->vlan);
|
||||||
|
|
||||||
|
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||||
|
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
|
||||||
|
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss)
|
||||||
|
{
|
||||||
|
vlan_dynamic_remove(hapd, oldbss->vlan);
|
||||||
|
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_vlan *vlan,
|
||||||
|
int vlan_id)
|
||||||
|
{
|
||||||
|
struct hostapd_vlan *n;
|
||||||
|
char *ifname, *pos;
|
||||||
|
|
||||||
|
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
|
||||||
|
vlan->vlan_id != VLAN_ID_WILDCARD)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ifname = os_strdup(vlan->ifname);
|
||||||
|
if (ifname == NULL)
|
||||||
|
return NULL;
|
||||||
|
pos = os_strchr(ifname, '#');
|
||||||
|
if (pos == NULL) {
|
||||||
|
os_free(ifname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*pos++ = '\0';
|
||||||
|
|
||||||
|
n = os_zalloc(sizeof(*n));
|
||||||
|
if (n == NULL) {
|
||||||
|
os_free(ifname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->vlan_id = vlan_id;
|
||||||
|
n->dynamic_vlan = 1;
|
||||||
|
|
||||||
|
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
|
||||||
|
pos);
|
||||||
|
os_free(ifname);
|
||||||
|
|
||||||
|
if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
|
||||||
|
os_free(n);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->next = hapd->conf->vlan;
|
||||||
|
hapd->conf->vlan = n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||||
|
{
|
||||||
|
struct hostapd_vlan *vlan;
|
||||||
|
|
||||||
|
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
vlan = hapd->conf->vlan;
|
||||||
|
while (vlan) {
|
||||||
|
if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
|
||||||
|
vlan->dynamic_vlan--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vlan = vlan->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlan == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (vlan->dynamic_vlan == 0)
|
||||||
|
hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
31
hostapd/vlan_init.h
Normal file
31
hostapd/vlan_init.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* hostapd / VLAN initialization
|
||||||
|
* Copyright 2003, Instant802 Networks, Inc.
|
||||||
|
* Copyright 2005, Devicescape Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of BSD
|
||||||
|
* license.
|
||||||
|
*
|
||||||
|
* See README and COPYING for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VLAN_INIT_H
|
||||||
|
#define VLAN_INIT_H
|
||||||
|
|
||||||
|
int vlan_init(struct hostapd_data *hapd);
|
||||||
|
void vlan_deinit(struct hostapd_data *hapd);
|
||||||
|
int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
|
||||||
|
struct hostapd_bss_config *oldbss);
|
||||||
|
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_vlan *vlan,
|
||||||
|
int vlan_id);
|
||||||
|
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
|
||||||
|
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||||
|
struct hostapd_ssid *mssid,
|
||||||
|
const char *dyn_vlan);
|
||||||
|
|
||||||
|
#endif /* VLAN_INIT_H */
|
40
hostapd/wired.conf
Normal file
40
hostapd/wired.conf
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
##### hostapd configuration file ##############################################
|
||||||
|
# Empty lines and lines starting with # are ignored
|
||||||
|
|
||||||
|
# Example configuration file for wired authenticator. See hostapd.conf for
|
||||||
|
# more details.
|
||||||
|
|
||||||
|
interface=eth0
|
||||||
|
driver=wired
|
||||||
|
logger_stdout=-1
|
||||||
|
logger_stdout_level=1
|
||||||
|
debug=2
|
||||||
|
dump_file=/tmp/hostapd.dump
|
||||||
|
|
||||||
|
ieee8021x=1
|
||||||
|
eap_reauth_period=3600
|
||||||
|
|
||||||
|
use_pae_group_addr=1
|
||||||
|
|
||||||
|
|
||||||
|
##### RADIUS configuration ####################################################
|
||||||
|
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
|
||||||
|
# authentication with external ACL for MAC addresses, and accounting
|
||||||
|
|
||||||
|
# The own IP address of the access point (used as NAS-IP-Address)
|
||||||
|
own_ip_addr=127.0.0.1
|
||||||
|
|
||||||
|
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
|
||||||
|
# a unique to the NAS within the scope of the RADIUS server. For example, a
|
||||||
|
# fully qualified domain name can be used here.
|
||||||
|
nas_identifier=ap.example.com
|
||||||
|
|
||||||
|
# RADIUS authentication server
|
||||||
|
auth_server_addr=127.0.0.1
|
||||||
|
auth_server_port=1812
|
||||||
|
auth_server_shared_secret=radius
|
||||||
|
|
||||||
|
# RADIUS accounting server
|
||||||
|
acct_server_addr=127.0.0.1
|
||||||
|
acct_server_port=1813
|
||||||
|
acct_server_shared_secret=radius
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue