First commit

This commit is contained in:
vemax78 2013-05-01 14:52:55 +02:00
commit 7dd6d43954
148 changed files with 32283 additions and 0 deletions

40
.autom4te.cfg Executable file
View File

@ -0,0 +1,40 @@
# SmartCAPWAP --
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
begin-language: "Autoheader-preselections"
args: --no-cache
end-language: "Autoheader-preselections"
begin-language: "Automake-preselections"
args: --no-cache
end-language: "Automake-preselections"
begin-language: "Autoreconf-preselections"
args: --no-cache
end-language: "Autoreconf-preselections"
begin-language: "Autoconf-without-aclocal-m4"
args: --no-cache
end-language: "Autoconf-without-aclocal-m4"
begin-language: "Autoconf"
args: --no-cache
end-language: "Autoconf"

1
.hgignore Normal file
View File

@ -0,0 +1 @@
build.sh

149
COPYING Normal file
View File

@ -0,0 +1,149 @@
SmartCAPWAP -- An Open Source CAPWAP WTP / AC
Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
This distribution contains multiple components, some
of which fall under different licenses. By using SmartCAPWAP
or any of the bundled components enumerated below, you
agree to be bound by the conditions of the license for
each respective component.
SmartCAPWAP license:
----------------
SmartCAPWAP is distributed under the GPL license version 2.
Libconfig license:
------------
Libconfig is Copyright (C) Mark Lindner,
and is licensed under the GPL license version 2.
OpenSSL License:
----------------
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
/* ====================================================================
* Copyright (c) 1998-2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED 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 OpenSSL PROJECT OR
* ITS 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.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
Original SSLeay License
-----------------------
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* 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 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC 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 THE AUTHOR 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.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
GNU Public License (GPL)
------------------------
SmartCAWAP, Libconfig distributions are
licensed under the GPL version 2 (see COPYRIGHT.GPL).

28
INSTALL Normal file
View File

@ -0,0 +1,28 @@
==================================================
HOW TO BUILD AND RUN SmartCAPWAP FOR LINUX SYSTEMS
==================================================
NOTE: To run WTP you must have a wireless card that has Linux driver based on the
Generic IEEE 802.11 Networking Stack (mac80211).
HOW TO BUILD AC AND WTP
=======================
Requirements
------------
* automake 1.9 or newer
* autoconf
* libtool
* openssl
Build
-----
Run:
autoreconf -f -i
./configure
make
make install

339
LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, 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 Lesser 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) <year> <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 Street, 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) year 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 Lesser General
Public License instead of this License.

34
Makefile.am Normal file
View File

@ -0,0 +1,34 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AUTOMAKE_OPTIONS = foreign 1.9
ACLOCAL_AMFLAGS = -I m4
MAINTAINERCLEANFILES = \
config.log config.status \
$(srcdir)/Makefile.in \
$(srcdir)/config.h.in $(srcdir)/config.h.in~ $(srcdir)/configure \
$(srcdir)/install-sh $(srcdir)/ltmain.sh $(srcdir)/missing \
$(srcdir)/m4/libtool.m4 $(srcdir)/m4/lt~obsolete.m4 \
$(srcdir)/m4/ltoptions.m4 $(srcdir)/m4/ltsugar.m4 \
$(srcdir)/m4/ltversion.m4 \
$(srcdir)/depcomp $(srcdir)/aclocal.m4 \
$(srcdir)/config.guess $(srcdir)/config.sub
SUBDIRS = build

31
build/Makefile.am Executable file
View File

@ -0,0 +1,31 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
SUBDIRS =
if BUILD_AC
SUBDIRS += ac
endif
if BUILD_WTP
SUBDIRS += wtp
endif

69
build/Makefile_common.am Executable file
View File

@ -0,0 +1,69 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
capwap_SOURCES = \
$(top_srcdir)/src/common/md5.c \
$(top_srcdir)/src/common/capwap.c \
$(top_srcdir)/src/common/capwap_network.c \
$(top_srcdir)/src/common/capwap_protocol.c \
$(top_srcdir)/src/common/capwap_logging.c \
$(top_srcdir)/src/common/capwap_list.c \
$(top_srcdir)/src/common/capwap_array.c \
$(top_srcdir)/src/common/capwap_dtls.c \
$(top_srcdir)/src/common/capwap_dfa.c \
$(top_srcdir)/src/common/capwap_element.c \
$(top_srcdir)/src/common/capwap_element_acdescriptor.c \
$(top_srcdir)/src/common/capwap_element_discoverytype.c \
$(top_srcdir)/src/common/capwap_element_wtpboarddata.c \
$(top_srcdir)/src/common/capwap_element_wtpdescriptor.c \
$(top_srcdir)/src/common/capwap_element_wtpframetunnelmode.c \
$(top_srcdir)/src/common/capwap_element_wtpmactype.c \
$(top_srcdir)/src/common/capwap_element_acname.c \
$(top_srcdir)/src/common/capwap_element_controlipv4.c \
$(top_srcdir)/src/common/capwap_element_controlipv6.c \
$(top_srcdir)/src/common/capwap_element_location.c \
$(top_srcdir)/src/common/capwap_element_wtpname.c \
$(top_srcdir)/src/common/capwap_element_sessionid.c \
$(top_srcdir)/src/common/capwap_element_ecnsupport.c \
$(top_srcdir)/src/common/capwap_element_localipv4.c \
$(top_srcdir)/src/common/capwap_element_localipv6.c \
$(top_srcdir)/src/common/capwap_element_transport.c \
$(top_srcdir)/src/common/capwap_element_mtudiscovery.c \
$(top_srcdir)/src/common/capwap_element_vendorpayload.c \
$(top_srcdir)/src/common/capwap_element_maximumlength.c \
$(top_srcdir)/src/common/capwap_element_wtprebootstat.c \
$(top_srcdir)/src/common/capwap_element_resultcode.c \
$(top_srcdir)/src/common/capwap_element_returnedmessage.c \
$(top_srcdir)/src/common/capwap_element_acipv4list.c \
$(top_srcdir)/src/common/capwap_element_acipv6list.c \
$(top_srcdir)/src/common/capwap_element_imageidentifier.c \
$(top_srcdir)/src/common/capwap_element_radioadmstate.c \
$(top_srcdir)/src/common/capwap_element_statisticstimer.c \
$(top_srcdir)/src/common/capwap_element_acnamepriority.c \
$(top_srcdir)/src/common/capwap_element_wtpstaticipaddress.c \
$(top_srcdir)/src/common/capwap_element_timers.c \
$(top_srcdir)/src/common/capwap_element_decrypterrorreportperiod.c \
$(top_srcdir)/src/common/capwap_element_idletimeout.c \
$(top_srcdir)/src/common/capwap_element_wtpfallback.c \
$(top_srcdir)/src/common/capwap_element_radiooprstate.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpradioinformation.c
if DEBUG_BUILD
capwap_SOURCES += $(top_srcdir)/src/common/capwap_debug.c
endif

64
build/ac/Makefile.am Executable file
View File

@ -0,0 +1,64 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
bin_PROGRAMS = ac
AM_CFLAGS = \
-DCAPWAP_MULTITHREADING_ENABLE \
-D_REENTRANT \
-D_GNU_SOURCE
if DTLS_ENABLED
AM_CFLAGS += $(SSL_CFLAGS)
endif
INCLUDES = \
-I$(top_srcdir)/build \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/ac
include $(top_srcdir)/build/Makefile_common.am
ac_SOURCES = \
$(capwap_SOURCES) \
$(top_srcdir)/src/common/capwap_event.c \
$(top_srcdir)/src/common/capwap_lock.c \
$(top_srcdir)/src/ac/ac.c \
$(top_srcdir)/src/ac/ac_execute.c \
$(top_srcdir)/src/ac/ac_session.c \
$(top_srcdir)/src/ac/ac_discovery.c \
$(top_srcdir)/src/ac/ac_dfa_join.c \
$(top_srcdir)/src/ac/ac_dfa_configure.c \
$(top_srcdir)/src/ac/ac_dfa_imagedata.c \
$(top_srcdir)/src/ac/ac_dfa_datacheck.c \
$(top_srcdir)/src/ac/ac_dfa_dtls.c \
$(top_srcdir)/src/ac/ac_dfa_run.c \
$(top_srcdir)/src/ac/ac_dfa_reset.c \
$(top_srcdir)/src/ac/ac_dfa_teardown.c
ac_LDADD = \
$(CONFIG_LIBS) \
$(PTHREAD_LIBS)
if DTLS_ENABLED
ac_LDADD += $(SSL_LIBS)
endif

60
build/wtp/Makefile.am Executable file
View File

@ -0,0 +1,60 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
bin_PROGRAMS = wtp
AM_CFLAGS = \
-D_REENTRANT \
-D_GNU_SOURCE
if DTLS_ENABLED
AM_CFLAGS += $(SSL_CFLAGS)
endif
INCLUDES = \
-I$(top_srcdir)/build \
-I$(top_srcdir)/src/common \
-I$(top_srcdir)/src/wtp
include $(top_srcdir)/build/Makefile_common.am
wtp_SOURCES = \
$(capwap_SOURCES) \
$(top_srcdir)/src/wtp/wtp.c \
$(top_srcdir)/src/wtp/wtp_dfa.c \
$(top_srcdir)/src/wtp/wtp_dfa_idle.c \
$(top_srcdir)/src/wtp/wtp_dfa_discovery.c \
$(top_srcdir)/src/wtp/wtp_dfa_sulking.c \
$(top_srcdir)/src/wtp/wtp_dfa_dtls.c \
$(top_srcdir)/src/wtp/wtp_dfa_join.c \
$(top_srcdir)/src/wtp/wtp_dfa_configure.c \
$(top_srcdir)/src/wtp/wtp_dfa_datacheck.c \
$(top_srcdir)/src/wtp/wtp_dfa_run.c \
$(top_srcdir)/src/wtp/wtp_dfa_reset.c \
$(top_srcdir)/src/wtp/wtp_dfa_imagedata.c
wtp_LDADD = \
$(CONFIG_LIBS)
if DTLS_ENABLED
wtp_LDADD += $(SSL_LIBS)
endif

81
conf/ac.conf Executable file
View File

@ -0,0 +1,81 @@
# AC configuration file
version = "1.0";
application: {
name = "ac 1";
binding = [
"802.11"
];
descriptor: {
maxstations = 20;
maxwtp = 10;
security: {
presharedkey = false;
x509 = false;
};
rmacfiled: {
supported = false;
};
dtlspolicy: {
cleardatachannel = true;
dtlsdatachannel = true;
};
info = (
{ idvendor = 12345; type = "hardware"; value = "1.0"; },
{ idvendor = 33457; type = "software"; value = "2.0"; }
);
};
ecn = "limited";
timer: {
discovery = 20;
echorequest = 30;
decrypterrorreport = 120;
idletimeout = 320;
};
wtpfallback = true;
dtls: {
enable = true;
type = "x509";
presharedkey: {
# TODO
};
x509: {
calist = "/etc/capwap/ca.crt";
certificate = "/etc/capwap/ac.crt";
privatekey = "/etc/capwap/ac.key";
privatekeypassword = "";
};
};
network: {
#binding = "eth1";
mtu = 1500;
transport = "udp";
ipv4 = true;
ipv6 = false;
ipdualstack = true;
};
};
logging: {
enable = true;
level = "debug";
output = (
{ mode = "stdout"; }
);
};

73
conf/ac.crt Normal file
View File

@ -0,0 +1,73 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=IT, ST=Italy, L=Rome, O=Capwap CA, CN=CAPWAP_CA/emailAddress=ca@localhost
Validity
Not Before: Apr 11 17:49:25 2009 GMT
Not After : Apr 9 17:49:25 2019 GMT
Subject: C=IT, ST=Italy, L=Rome, O=Capwap AC, CN=CAPWAP_AC/emailAddress=ac@localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:e2:9f:90:f6:f5:c5:52:23:cc:8d:28:6c:7c:0b:
4a:ec:0d:50:de:0d:37:0d:de:75:cb:61:d8:58:e3:
3f:ec:cb:5b:b5:e0:ca:87:93:cf:22:f3:7d:35:cf:
2d:ef:ad:a4:8a:d3:8c:ec:7f:d2:7e:19:cb:11:15:
28:b0:ee:74:33:e2:21:24:70:d0:e4:22:2f:eb:59:
3d:ef:c4:c2:1b:f7:7d:1b:ac:3c:f8:46:c9:0a:f4:
12:b0:71:11:0d:52:84:d9:a9:76:84:68:33:c6:7c:
54:1a:4c:34:f4:22:ad:fb:4c:7b:2e:ee:1a:fe:b3:
0d:18:38:16:46:48:9d:7a:b7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
Easy-RSA Generated Server Certificate
X509v3 Subject Key Identifier:
63:7B:01:7C:B6:2B:DC:D5:E4:BD:A1:AC:D4:BB:E0:6F:A6:07:16:A4
X509v3 Authority Key Identifier:
keyid:49:62:46:06:E1:E5:D3:3A:08:79:C6:D6:FE:93:A8:D9:AA:75:EB:E4
DirName:/C=IT/ST=Italy/L=Rome/O=Capwap CA/CN=CAPWAP_CA/emailAddress=ca@localhost
serial:94:59:55:20:58:F6:66:33
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha1WithRSAEncryption
0a:be:9e:6c:a1:c6:0c:a6:d3:5e:92:6b:09:21:78:99:f0:83:
a1:a4:2f:56:56:55:51:61:f4:04:a5:fe:9a:c4:95:76:01:f3:
72:96:18:e2:96:f9:8d:cf:6d:32:6c:39:9c:92:a2:41:39:e2:
3f:32:ef:73:75:f0:3e:f4:9c:93:af:31:63:c7:55:2e:8d:de:
ab:99:59:82:36:54:49:ef:ef:13:a7:26:db:8f:2e:93:0c:a1:
d5:b5:e6:5d:7a:a4:3f:1d:8e:ad:73:c5:32:ba:24:d2:4a:f5:
ae:95:18:98:07:80:fc:be:95:45:ce:50:ab:fc:6e:90:7a:8b:
28:5d
-----BEGIN CERTIFICATE-----
MIIDmTCCAwKgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJJVDEO
MAwGA1UECBMFSXRhbHkxDTALBgNVBAcTBFJvbWUxEjAQBgNVBAoTCUNhcHdhcCBD
QTESMBAGA1UEAxQJQ0FQV0FQX0NBMRswGQYJKoZIhvcNAQkBFgxjYUBsb2NhbGhv
c3QwHhcNMDkwNDExMTc0OTI1WhcNMTkwNDA5MTc0OTI1WjBxMQswCQYDVQQGEwJJ
VDEOMAwGA1UECBMFSXRhbHkxDTALBgNVBAcTBFJvbWUxEjAQBgNVBAoTCUNhcHdh
cCBBQzESMBAGA1UEAxQJQ0FQV0FQX0FDMRswGQYJKoZIhvcNAQkBFgxhY0Bsb2Nh
bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOKfkPb1xVIjzI0obHwL
SuwNUN4NNw3edcth2FjjP+zLW7XgyoeTzyLzfTXPLe+tpIrTjOx/0n4ZyxEVKLDu
dDPiISRw0OQiL+tZPe/Ewhv3fRusPPhGyQr0ErBxEQ1ShNmpdoRoM8Z8VBpMNPQi
rftMey7uGv6zDRg4FkZInXq3AgMBAAGjggE/MIIBOzAJBgNVHRMEAjAAMBEGCWCG
SAGG+EIBAQQEAwIGQDA0BglghkgBhvhCAQ0EJxYlRWFzeS1SU0EgR2VuZXJhdGVk
IFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUY3sBfLYr3NXkvaGs1Lvgb6YH
FqQwgaMGA1UdIwSBmzCBmIAUSWJGBuHl0zoIecbW/pOo2ap16+ShdaRzMHExCzAJ
BgNVBAYTAklUMQ4wDAYDVQQIEwVJdGFseTENMAsGA1UEBxMEUm9tZTESMBAGA1UE
ChMJQ2Fwd2FwIENBMRIwEAYDVQQDFAlDQVBXQVBfQ0ExGzAZBgkqhkiG9w0BCQEW
DGNhQGxvY2FsaG9zdIIJAJRZVSBY9mYzMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsG
A1UdDwQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQAKvp5socYMptNekmsJIXiZ8IOh
pC9WVlVRYfQEpf6axJV2AfNylhjilvmNz20ybDmckqJBOeI/Mu9zdfA+9JyTrzFj
x1Uujd6rmVmCNlRJ7+8Tpybbjy6TDKHVteZdeqQ/HY6tc8UyuiTSSvWulRiYB4D8
vpVFzlCr/G6QeosoXQ==
-----END CERTIFICATE-----

15
conf/ac.key Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDin5D29cVSI8yNKGx8C0rsDVDeDTcN3nXLYdhY4z/sy1u14MqH
k88i8301zy3vraSK04zsf9J+GcsRFSiw7nQz4iEkcNDkIi/rWT3vxMIb930brDz4
RskK9BKwcRENUoTZqXaEaDPGfFQaTDT0Iq37THsu7hr+sw0YOBZGSJ16twIDAQAB
AoGAM0gEV735rsKnEPIqyk8L3yqMOBMpeBv079buS/7wgjbqQ9fgPJm376LFnJ2L
OYdDip6gbwvlp99SUkVFdfQfmwjmBDk1IfEWYiPO4CUrsIUzid2KtueZW5c6Cm0Q
RMutCQrsZw9s6VpL9bmV0zsm3MYNYfERs0rPOIW9I3YyrEECQQD5t5V4Uj7+gpZO
Qvb+tYAVb8NcYTPBfdVbZJ8MRrs9tH2Y2AkuE1D+g7S5qq+Ld1tBIcCeKhlG4+ee
ClH20s3RAkEA6FM8eGKOhZ4nmu4yzwdMJnqY0d4+56805VS5Z+uJJiXvCXKQ+wQr
e/8BLsWRLxXlqijshsWzHID2g8i/rlC6BwJADiHqrqWQ9Rx03zcA/YdOGWh62PaT
VEcH1SVLrwktvZ9CYG0Rj+797XmMt9lGGBGIM5ZybUEarx1k1VfmLZ7ekQJAKPOD
FTVKKgNWt9iE3DlNEvtJNLUYIX6gtEva4paB9ld5axDmvVhe0dyBON1aWhJiCTxt
dNQkXkHdMh2QrAlOwQJAcoEhG5Zl0wATXSCFvbvaJKiH9Ab1IjlCtNI3O/+TgQjN
ZQMA0nO5ZJ3p266M8zh2hgIRdNstv4oilqh/3DnO3g==
-----END RSA PRIVATE KEY-----

20
conf/ca.crt Normal file
View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDNzCCAqCgAwIBAgIJAJRZVSBY9mYzMA0GCSqGSIb3DQEBBQUAMHExCzAJBgNV
BAYTAklUMQ4wDAYDVQQIEwVJdGFseTENMAsGA1UEBxMEUm9tZTESMBAGA1UEChMJ
Q2Fwd2FwIENBMRIwEAYDVQQDFAlDQVBXQVBfQ0ExGzAZBgkqhkiG9w0BCQEWDGNh
QGxvY2FsaG9zdDAeFw0wOTA0MTExNzQ2MzlaFw0xOTA0MDkxNzQ2MzlaMHExCzAJ
BgNVBAYTAklUMQ4wDAYDVQQIEwVJdGFseTENMAsGA1UEBxMEUm9tZTESMBAGA1UE
ChMJQ2Fwd2FwIENBMRIwEAYDVQQDFAlDQVBXQVBfQ0ExGzAZBgkqhkiG9w0BCQEW
DGNhQGxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAw0gvx6qo
B4fd23/dU5yBdj/TKzVM1/kC/bwRRFjNd2FIMpjsJ7drbwhZo5CrOSFyKn8X4Exr
EdkfMjjNFi6mZVmdFfJO4ex+6qJqc1m52AocUEOkyG/52LOnCTsT91yps97obPUF
8ezK0m9a5dnuoJ8q7lxbGu7m0PJ0Qgws3dsCAwEAAaOB1jCB0zAdBgNVHQ4EFgQU
SWJGBuHl0zoIecbW/pOo2ap16+QwgaMGA1UdIwSBmzCBmIAUSWJGBuHl0zoIecbW
/pOo2ap16+ShdaRzMHExCzAJBgNVBAYTAklUMQ4wDAYDVQQIEwVJdGFseTENMAsG
A1UEBxMEUm9tZTESMBAGA1UEChMJQ2Fwd2FwIENBMRIwEAYDVQQDFAlDQVBXQVBf
Q0ExGzAZBgkqhkiG9w0BCQEWDGNhQGxvY2FsaG9zdIIJAJRZVSBY9mYzMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAsHOGDPcwslke/Ux3bp2tZj4MizTL
DJqTRbqoiQLOTfUI7KU0GQ2m+ywTwhpiUPhmqqmgtGKXbL9mQB/qcG6HGNzdRc56
4ttc1RVErhmM/LZEFjyHamuOryUY5FmS78XXBGFRkvPAap9OSQU4vXPfehYFCL+p
/L9CoKunApUqH3g=
-----END CERTIFICATE-----

110
conf/wtp.conf Executable file
View File

@ -0,0 +1,110 @@
# WTP configuration file
version = "1.0";
application: {
name = "wtp 1";
location = "Ufficio";
binding = "802.11";
tunnelmode: {
nativeframe = false;
ethframe = false;
localbridging = false;
};
mactype = "localmac";
boardinfo: {
idvendor = 123456;
element = (
{ name = "model"; value = "1.0"; },
{ name = "serial"; value = "2.0"; },
{ name = "id"; value = "3.0"; },
{ name = "revision"; value = "4.0"; },
{ name = "macaddress"; type = "interface"; value = "eth1"; }
);
};
descriptor: {
radio = (
{ device = "wifi0"; type = "bg"; status = "enabled"; }
);
encryption = [
"802.11_AES",
"802.11_TKIP"
];
info = (
{ idvendor = 23456; type = "hardware"; value = "abcde"; },
{ idvendor = 33457; type = "software"; value = "fghil"; },
{ idvendor = 43458; type = "boot"; value = "mnopq"; },
{ idvendor = 53459; type = "other"; value = "qwert"; }
);
};
ecn = "limited";
timer: {
statistics = 120;
};
dtls: {
enable = true;
dtlspolicy: {
cleardatachannel = true;
dtlsdatachannel = true;
};
type = "x509";
presharedkey: {
# TODO
};
x509: {
calist = "/etc/capwap/ca.crt";
certificate = "/etc/capwap/wtp.crt";
privatekey = "/etc/capwap/wtp.key";
privatekeypassword = "";
};
};
network: {
#binding = "eth1";
mtu = 1500;
port = 10000;
transport = "udp";
ipv4 = true;
ipv6 = false;
ipdualstack = true;
};
acdiscovery: {
search = false;
host = [
"127.0.0.1"
];
};
acprefered: {
host = [
"127.0.0.1"
];
};
};
logging: {
enable = true;
level = "debug";
output = (
{ mode = "stdout"; }
);
};

70
conf/wtp.crt Normal file
View File

@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=IT, ST=Italy, L=Rome, O=Capwap CA, CN=CAPWAP_CA/emailAddress=ca@localhost
Validity
Not Before: Apr 11 17:50:00 2009 GMT
Not After : Apr 9 17:50:00 2019 GMT
Subject: C=IT, ST=Italy, L=Rome, O=Capwap WTP, CN=CAPWAP_WTP/emailAddress=wtp@localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:d4:78:02:6f:d8:52:3b:ea:7c:13:a9:d4:74:58:
4c:d9:6d:e9:54:76:ea:6c:74:8a:70:b7:f8:72:9e:
71:63:bc:db:6e:43:d8:c6:6b:34:94:e4:28:98:a2:
5b:16:9e:a8:9e:19:50:61:01:d3:f6:fd:37:e7:8b:
be:9e:bf:bc:96:c2:3e:d3:fa:fe:1a:76:42:5c:92:
76:73:1f:97:94:42:38:93:d0:56:a5:b2:b1:5f:ba:
90:90:17:f4:88:cb:c6:35:9b:7d:0f:a4:75:6d:d2:
bb:b2:1d:cf:55:9d:e7:9b:03:35:fe:6f:1b:df:10:
3d:58:7b:77:1c:e5:ba:a5:75
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
Easy-RSA Generated Certificate
X509v3 Subject Key Identifier:
53:EB:37:11:23:CC:27:53:89:04:2F:08:C5:05:47:D4:65:23:73:2D
X509v3 Authority Key Identifier:
keyid:49:62:46:06:E1:E5:D3:3A:08:79:C6:D6:FE:93:A8:D9:AA:75:EB:E4
DirName:/C=IT/ST=Italy/L=Rome/O=Capwap CA/CN=CAPWAP_CA/emailAddress=ca@localhost
serial:94:59:55:20:58:F6:66:33
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Key Usage:
Digital Signature
Signature Algorithm: sha1WithRSAEncryption
57:93:d6:43:0b:e6:5f:b7:77:2c:1d:d3:b0:4c:6a:35:62:ec:
5b:56:e5:f7:34:b9:c7:8d:9f:e7:cb:12:0d:f0:cf:c7:a3:c1:
24:0f:64:f2:a2:ab:f7:80:e8:a5:66:8a:c3:2f:9b:4f:87:d7:
8e:27:e7:29:73:cc:fc:4c:0d:fb:8f:74:ee:7c:bd:ce:d3:01:
ee:69:1f:42:56:6f:e1:b3:6c:c3:a1:4d:60:14:06:ba:a7:38:
a0:78:1d:a9:cd:39:90:f2:33:6c:fb:48:cb:6e:80:00:ce:7c:
50:e2:e7:6f:83:f1:86:be:39:5c:0c:64:1f:01:7c:1b:9f:e6:
ea:e2
-----BEGIN CERTIFICATE-----
MIIDgjCCAuugAwIBAgIBAzANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJJVDEO
MAwGA1UECBMFSXRhbHkxDTALBgNVBAcTBFJvbWUxEjAQBgNVBAoTCUNhcHdhcCBD
QTESMBAGA1UEAxQJQ0FQV0FQX0NBMRswGQYJKoZIhvcNAQkBFgxjYUBsb2NhbGhv
c3QwHhcNMDkwNDExMTc1MDAwWhcNMTkwNDA5MTc1MDAwWjB0MQswCQYDVQQGEwJJ
VDEOMAwGA1UECBMFSXRhbHkxDTALBgNVBAcTBFJvbWUxEzARBgNVBAoTCkNhcHdh
cCBXVFAxEzARBgNVBAMUCkNBUFdBUF9XVFAxHDAaBgkqhkiG9w0BCQEWDXd0cEBs
b2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANR4Am/YUjvqfBOp
1HRYTNlt6VR26mx0inC3+HKecWO8225D2MZrNJTkKJiiWxaeqJ4ZUGEB0/b9N+eL
vp6/vJbCPtP6/hp2QlySdnMfl5RCOJPQVqWysV+6kJAX9IjLxjWbfQ+kdW3Su7Id
z1Wd55sDNf5vG98QPVh7dxzluqV1AgMBAAGjggElMIIBITAJBgNVHRMEAjAAMC0G
CWCGSAGG+EIBDQQgFh5FYXN5LVJTQSBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYD
VR0OBBYEFFPrNxEjzCdTiQQvCMUFR9RlI3MtMIGjBgNVHSMEgZswgZiAFEliRgbh
5dM6CHnG1v6TqNmqdevkoXWkczBxMQswCQYDVQQGEwJJVDEOMAwGA1UECBMFSXRh
bHkxDTALBgNVBAcTBFJvbWUxEjAQBgNVBAoTCUNhcHdhcCBDQTESMBAGA1UEAxQJ
Q0FQV0FQX0NBMRswGQYJKoZIhvcNAQkBFgxjYUBsb2NhbGhvc3SCCQCUWVUgWPZm
MzATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEF
BQADgYEAV5PWQwvmX7d3LB3TsExqNWLsW1bl9zS5x42f58sSDfDPx6PBJA9k8qKr
94DopWaKwy+bT4fXjifnKXPM/EwN+4907ny9ztMB7mkfQlZv4bNsw6FNYBQGuqc4
oHgdqc05kPIzbPtIy26AAM58UOLnb4Pxhr45XAxkHwF8G5/m6uI=
-----END CERTIFICATE-----

15
conf/wtp.key Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDUeAJv2FI76nwTqdR0WEzZbelUdupsdIpwt/hynnFjvNtuQ9jG
azSU5CiYolsWnqieGVBhAdP2/Tfni76ev7yWwj7T+v4adkJcknZzH5eUQjiT0Fal
srFfupCQF/SIy8Y1m30PpHVt0ruyHc9VneebAzX+bxvfED1Ye3cc5bqldQIDAQAB
AoGAAIP2BY1xzaFpAac0079vGEvy9/h94xt5RoK7wJNv1P0dTyws93ZFH2NaUdx6
+hgScqe/ES0u9XdxzkcBhGMUswvNmofgk9w/ynQhey7g739TXeEh76zMphNVJf0z
pawFFP/FIIgYVf7CdHkQ8cU4LEvTUCxAE5bICHMuOgCiEQECQQDz5/PSc/ZuMOZq
ngYOCaf3p3CQdeFcFOeU3ldxW8j5eZR2Xdhu5CCeY5ELPq+yW4+J+6KBAVh6Q8Uv
MwDCSqrBAkEA3wEBMgaJvpEijv6P6Ryc+khazEASDAbvUmrcUD0t14aPrCoAHAUU
stCCcn8zV4MqETPr7bO9joh/oh7IpCGrtQJAMYzTydNpIuWoScykqkFn8DYB9jcc
e1p72ZB57zuYTqZWdN2H1K9fuQ29L62if/d956hJUS/2y4/tBTO1WcNVgQJBALQK
jJuF2cmoRV1rOma6+iW7KstCYw+gvbEtoyeI7SzXb8FQu3vjwj1HyDmGZr4doGX5
JF5pwf2ESH9sGRMiOA0CQGKVeegxodjqwNEY8WqJjgROHkI1aJhdHVehAcCLhtGX
WBcQEK73GJC5Kb4yTg0VEFkIWeGpy0aDnOyTJlNrQKc=
-----END RSA PRIVATE KEY-----

230
configure.ac Normal file
View File

@ -0,0 +1,230 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC
#
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
#
# 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 (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AC_PREREQ(2.60)
m4_include(version.m4)
AC_INIT([PRODUCT_NAME], [PRODUCT_VERSION], [PRODUCT_BUGREPORT], [PRODUCT_TARNAME])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE
# cross-compile macros
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
#
AC_COPYRIGHT("SmartCapwap by Massimo Vellucci <vemax78@gmail.com>")
AC_REVISION($Revision: 1.0 $)
#
AC_ARG_ENABLE(
[dtls],
[AS_HELP_STRING([--disable-dtls], [disable DTLS support @<:@default=yes@:>@])],
,
[enable_dtls="yes"]
)
AC_ARG_ENABLE(
[debug],
[AS_HELP_STRING([--disable-debug], [disable debug support @<:@default=yes@:>@])],
,
[enable_debug="yes"]
)
AC_ARG_ENABLE(
[logging],
[AS_HELP_STRING([--disable-logging], [disable logging support @<:@default=yes@:>@])],
,
[enable_logging="yes"]
)
AC_ARG_ENABLE(
[ac],
[AS_HELP_STRING([--disable-ac], [disable ac support @<:@default=yes@:>@])],
,
[enable_ac="yes"]
)
AC_ARG_ENABLE(
[wtp],
[AS_HELP_STRING([--disable-wtp], [disable wtp support @<:@default=yes@:>@])],
,
[enable_wtp="yes"]
)
AC_ARG_WITH(
[ssl-library],
[AS_HELP_STRING([--with-crypto-library=library], [build with the given crypto library, TYPE=openssl @<:@default=openssl@:>@])],
[
case "${withval}" in
openssl) ;;
*) AC_MSG_ERROR([bad value ${withval} for --with-crypto-library]) ;;
esac
],
[with_ssl_library="openssl"]
)
AC_ARG_WITH(
[mem-check],
[AS_HELP_STRING([--with-mem-check=TYPE], [build with debug memory checking, TYPE=no|internal|valgrind @<:@default=internal@:>@])],
[
case "${withval}" in
valgrind|internal|no) ;;
*) AC_MSG_ERROR([bad value ${withval} for --mem-check]) ;;
esac
],
[with_mem_check="internal"]
)
# specify output header file
AM_CONFIG_HEADER(build/config.h)
#
old_CFLAGS="${CFLAGS}"
AC_PROG_CC([gcc])
CFLAGS="${old_CFLAGS}"
#
AM_CONDITIONAL([DEBUG_BUILD], [test "$enable_debug" = yes])
if test "${enable_debug}" = "yes"; then
CFLAGS="${CFLAGS} -DDEBUG -Wall -Werror -g -O0"
else
CFLAGS="${CFLAGS} -O2"
fi
#
AC_PROG_INSTALL
AC_USE_SYSTEM_EXTENSIONS
AC_LANG(C)
AC_HEADER_STDC
# Check LIBCONFIG library
AC_CHECK_HEADER([libconfig.h], [], [AC_MSG_ERROR(You need the libconfig headers)])
AC_CHECK_LIB([config], [config_init], [CONFIG_LIBS="-lconfig"], [AC_MSG_ERROR(You need the libconfig library)])
# Check PTHREAD library
AC_CHECK_HEADER([pthread.h], [], [AC_MSG_ERROR(You need the pthread headers)])
AC_CHECK_LIB([pthread], [pthread_create], [PTHREAD_LIBS="-lpthread"], [AC_MSG_ERROR(You need the pthread library)])
# Check SSL library
PKG_CHECK_MODULES(
[OPENSSL_CRYPTO],
[libcrypto >= 1.0.0],
[have_openssl_crypto="yes"],
[AC_CHECK_LIB(
[crypto],
[RSA_new],
[
have_openssl_crypto="yes"
OPENSSL_CRYPTO_LIBS="-lcrypto"
]
)]
)
PKG_CHECK_MODULES(
[OPENSSL_SSL],
[libssl >= 1.0.0],
[have_openssl_ssl="yes"],
[AC_CHECK_LIB(
[ssl],
[SSL_CTX_new],
[
have_openssl_ssl="yes"
OPENSSL_SSL_LIBS="-lssl"
]
)]
)
if test "${have_openssl_ssl}" = "yes"; then
saved_CFLAGS="${CFLAGS}"
saved_LIBS="${LIBS}"
CFLAGS="${CFLAGS} ${OPENSSL_SSL_CFLAGS}"
LIBS="${LIBS} ${OPENSSL_SSL_LIBS}"
have_openssl_engine="yes"
AC_CHECK_FUNC([SSL_CTX_set_cookie_generate_cb], , [AC_MSG_ERROR([${with_ssl_library} SSL_CTX_set_cookie_generate_cb function is required but missing])])
AC_CHECK_FUNC([SSL_CTX_set_cookie_verify_cb], , [AC_MSG_ERROR([${with_ssl_library} SSL_CTX_set_cookie_verify_cb function is required but missing])])
CFLAGS="${saved_CFLAGS}"
LIBS="${saved_LIBS}"
fi
case "${with_ssl_library}" in
openssl)
have_crypto_engine="${have_openssl_engine}"
have_crypto_crypto="${have_openssl_crypto}"
have_crypto_ssl="${have_openssl_ssl}"
SSL_CFLAGS="${OPENSSL_CRYPTO_CFLAGS} ${OPENSSL_SSL_CFLAGS}"
SSL_LIBS="${OPENSSL_SSL_LIBS}"
test "${have_openssl_engine}" = "yes" && AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [Use crypto library])
;;
esac
if test "${enable_dtls}" = "yes"; then
test "${have_crypto_engine}" != "yes" && AC_MSG_ERROR([${with_ssl_library} engine is required but missing])
test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_ssl_library} crypto is required but missing])
test "${have_crypto_ssl}" != "yes" && AC_MSG_ERROR([${with_ssl_library} ssl is required but missing])
AC_DEFINE([ENABLE_DTLS], [1], [Enable DTLS])
fi
# Memory check
case "${with_mem_check}" in
internal)
LIBS="${LIBS} -rdynamic"
AC_DEFINE([USE_INTERNAL_MEMCHECK], [1], [Use internal memory debugging])
;;
valgrind)
AC_CHECK_HEADER(
[valgrind/memcheck.h],
[
CFLAGS="${CFLAGS} -g -fno-inline"
AC_DEFINE([USE_VALGRIND_MEMCHECK], [1], [Use valgrind memory debugging library])
],
[AC_MSG_ERROR([valgrind headers not found.])]
)
;;
esac
#
AM_CONDITIONAL([BUILD_AC], [test "${enable_ac}" = "yes"])
AM_CONDITIONAL([BUILD_WTP], [test "${enable_wtp}" = "yes"])
#
test "${enable_logging}" = "yes" && AC_DEFINE([ENABLE_LOGGING], [1], [Enable logging])
#
AM_CONDITIONAL([BUILD_DEBUG], [test "${enable_debug}" = "yes"])
AM_CONDITIONAL([DTLS_ENABLED], [test "${enable_dtls}" = "yes"])
#
AC_SUBST([SSL_CFLAGS])
AC_SUBST([SSL_LIBS])
AC_SUBST([CONFIG_LIBS])
AC_SUBST([PTHREAD_LIBS])
#
AC_CONFIG_FILES([
Makefile
build/Makefile
build/ac/Makefile
build/wtp/Makefile
])
AC_OUTPUT

8683
docs/rfc5415.txt Normal file

File diff suppressed because it is too large Load Diff

4259
docs/rfc5416.txt Normal file

File diff suppressed because it is too large Load Diff

655
src/ac/ac.c Normal file
View File

@ -0,0 +1,655 @@
#include "ac.h"
#include "capwap_dtls.h"
#include <libconfig.h>
#ifndef CAPWAP_MULTITHREADING_ENABLE
#error "AC request multithreading\n"
#endif
struct ac_t g_ac;
#define AC_STANDARD_NAME "Unknown AC"
/* Local param */
static char g_configurationfile[260] = AC_DEFAULT_CONFIGURATION_FILE;
/* Alloc AC */
static int ac_init(void) {
/* Network */
capwap_network_init(&g_ac.net);
g_ac.mtu = CAPWAP_MTU_DEFAULT;
g_ac.binding = capwap_array_create(sizeof(unsigned short), 0);
/* Standard name */
strcpy(g_ac.acname.name, AC_STANDARD_NAME);
/* Descriptor */
g_ac.descriptor.stationlimit = AC_DEFAULT_MAXSTATION;
g_ac.descriptor.wtplimit = AC_DEFAULT_MAXSESSIONS;
g_ac.descriptor.security = 0;
g_ac.descriptor.rmacfield = CAPWAP_ACDESC_RMACFIELD_NOTSUPPORTED;
g_ac.descriptor.dtlspolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
g_ac.descriptor.descsubelement = capwap_array_create(sizeof(struct capwap_acdescriptor_desc_subelement), 0);
/* */
g_ac.dfa.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
g_ac.dfa.transport.type = CAPWAP_UDP_TRANSPORT;
/* */
g_ac.dfa.timers.discovery = AC_DEFAULT_DISCOVERY_INTERVAL;
g_ac.dfa.timers.echorequest = AC_DEFAULT_ECHO_INTERVAL;
g_ac.dfa.decrypterrorreport_interval = AC_DEFAULT_DECRYPT_ERROR_PERIOD_INTERVAL;
g_ac.dfa.idletimeout.timeout = AC_DEFAULT_IDLE_TIMEOUT_INTERVAL;
g_ac.dfa.wtpfallback.mode = AC_DEFAULT_WTP_FALLBACK_MODE;
/* */
g_ac.dfa.acipv4list = capwap_array_create(sizeof(struct capwap_acipv4list_element), 0);
g_ac.dfa.acipv6list = capwap_array_create(sizeof(struct capwap_acipv6list_element), 0);
/* */
g_ac.dfa.rfcWaitJoin = AC_DEFAULT_WAITJOIN_INTERVAL;
g_ac.dfa.rfcWaitDTLS = AC_DEFAULT_WAITDTLS_INTERVAL;
g_ac.dfa.rfcChangeStatePendingTimer = AC_DEFAULT_CHANGE_STATE_PENDING_TIMER;
g_ac.dfa.rfcDataCheckTimer = AC_DEFAULT_DATA_CHECK_TIMER;
/* Sessions */
capwap_event_init(&g_ac.changesessionlist);
g_ac.sessions = capwap_list_create();
capwap_lock_init(&g_ac.sessionslock);
g_ac.datasessionshandshake = capwap_list_create();
return 1;
}
/* Destroy AC */
static void ac_destroy(void) {
/* Dtls */
capwap_crypt_freecontext(&g_ac.dtlscontext);
/* */
capwap_array_free(g_ac.descriptor.descsubelement);
capwap_array_free(g_ac.binding);
/* */
capwap_array_free(g_ac.dfa.acipv4list);
capwap_array_free(g_ac.dfa.acipv6list);
/* Sessions */
capwap_list_free(g_ac.sessions);
capwap_lock_destroy(&g_ac.sessionslock);
capwap_event_destroy(&g_ac.changesessionlist);
capwap_list_free(g_ac.datasessionshandshake);
}
/* Help */
static void ac_print_usage(void) {
}
/* Parsing configuration */
static int ac_parsing_configuration_1_0(config_t* config) {
int i;
int configInt;
int configIPv4;
int configIPv6;
long int configLongInt;
const char* configString;
config_setting_t* configSetting;
/* Logging configuration */
if (config_lookup_bool(config, "logging.enable", &configInt) == CONFIG_TRUE) {
if (!configInt) {
capwap_logging_verboselevel(CAPWAP_LOGGING_NONE);
capwap_logging_disable_allinterface();
} else {
if (config_lookup_string(config, "logging.level", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "fatal")) {
capwap_logging_verboselevel(CAPWAP_LOGGING_FATAL);
} else if (!strcmp(configString, "error")) {
capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR);
} else if (!strcmp(configString, "warning")) {
capwap_logging_verboselevel(CAPWAP_LOGGING_WARNING);
} else if (!strcmp(configString, "info")) {
capwap_logging_verboselevel(CAPWAP_LOGGING_INFO);
} else if (!strcmp(configString, "debug")) {
capwap_logging_verboselevel(CAPWAP_LOGGING_DEBUG);
} else {
capwap_logging_error("Invalid configuration file, unknown logging.level value");
return 0;
}
}
/* Logging output interface */
configSetting = config_lookup(config, "logging.output");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
/* Disable output interface */
capwap_logging_disable_allinterface();
/* Enable selected interface */
for (i = 0; i < count; i++) {
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
if ((configElement != NULL) && (config_setting_lookup_string(configElement, "mode", &configString) == CONFIG_TRUE)) {
if (!strcmp(configString, "stdout")) {
capwap_logging_enable_console(0);
} else if (!strcmp(configString, "stderr")) {
capwap_logging_enable_console(1);
} else {
capwap_logging_error("Invalid configuration file, unknown logging.output value");
return 0;
}
}
}
}
}
}
/* Set name of AC */
if (config_lookup_string(config, "application.name", &configString) == CONFIG_TRUE) {
if (strlen(configString) > CAPWAP_ACNAME_MAXLENGTH) {
capwap_logging_error("Invalid configuration file, application.name string length exceeded");
return 0;
}
strcpy(g_ac.acname.name, configString);
}
/* Set binding of AC */
configSetting = config_lookup(config, "application.binding");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* bindingName = config_setting_get_string_elem(configSetting, i);
if (bindingName != NULL) {
unsigned short* binding = (unsigned short*)capwap_array_get_item_pointer(g_ac.binding, g_ac.binding->count);
if (!strcmp(bindingName, "802.11")) {
*binding = CAPWAP_WIRELESS_BINDING_IEEE80211;
} else if (!strcmp(bindingName, "EPCGlobal")) {
*binding = CAPWAP_WIRELESS_BINDING_EPCGLOBAL;
} else {
capwap_logging_error("Invalid configuration file, unknown application.binding value");
return 0;
}
}
}
}
/* Set max stations of AC */
if (config_lookup_int(config, "application.descriptor.maxstations", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt > 0) && (configLongInt < 65536)) {
g_ac.descriptor.stationlimit = (unsigned short)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, unknown application.descriptor.maxstations value");
return 0;
}
}
/* Set max wtp of AC */
if (config_lookup_int(config, "application.descriptor.maxwtp", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt > 0) && (configLongInt < 65536)) {
g_ac.descriptor.wtplimit = (unsigned short)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, unknown application.descriptor.maxwtp value");
return 0;
}
}
/* Set security of AC */
if (config_lookup(config, "application.descriptor.security") != NULL) {
g_ac.descriptor.security = 0;
if (config_lookup_bool(config, "application.descriptor.security.presharedkey", &configInt) == CONFIG_TRUE) {
if (configInt != 0) {
g_ac.descriptor.security |= CAPWAP_ACDESC_SECURITY_PRESHARED_KEY;
}
}
if (config_lookup_bool(config, "application.descriptor.security.x509", &configInt) == CONFIG_TRUE) {
if (configInt != 0) {
g_ac.descriptor.security |= CAPWAP_ACDESC_SECURITY_X509_CERT;
}
}
}
/* Set rmacfiled of AC */
if (config_lookup_bool(config, "application.descriptor.rmacfiled.supported", &configInt) == CONFIG_TRUE) {
g_ac.descriptor.rmacfield = ((configInt != 0) ? CAPWAP_ACDESC_RMACFIELD_SUPPORTED : CAPWAP_ACDESC_RMACFIELD_NOTSUPPORTED);
}
/* Set DTLS policy of AC */
if (config_lookup(config, "application.descriptor.dtlspolicy") != NULL) {
g_ac.descriptor.dtlspolicy = 0;
if (config_lookup_bool(config, "application.descriptor.dtlspolicy.cleardatachannel", &configInt) == CONFIG_TRUE) {
if (configInt != 0) {
g_ac.descriptor.dtlspolicy |= CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
}
}
if (config_lookup_bool(config, "application.descriptor.dtlspolicy.dtlsdatachannel", &configInt) == CONFIG_TRUE) {
if (configInt != 0) {
g_ac.descriptor.dtlspolicy |= CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED;
}
}
}
/* Set info descriptor of AC */
configSetting = config_lookup(config, "application.descriptor.info");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
config_setting_t* configElement = config_setting_get_elem(configSetting, i);
if (configElement != NULL) {
long int configVendor;
if (config_setting_lookup_int(configElement, "idvendor", &configVendor) == CONFIG_TRUE) {
const char* configType;
if (config_setting_lookup_string(configElement, "type", &configType) == CONFIG_TRUE) {
const char* configValue;
if (config_setting_lookup_string(configElement, "value", &configValue) == CONFIG_TRUE) {
int lengthValue = strlen(configValue);
if (lengthValue < CAPWAP_ACDESC_SUBELEMENT_MAXDATA) {
unsigned short type;
struct capwap_acdescriptor_desc_subelement* desc;
if (!strcmp(configType, "hardware")) {
type = CAPWAP_ACDESC_SUBELEMENT_HARDWAREVERSION;
} else if (!strcmp(configType, "software")) {
type = CAPWAP_ACDESC_SUBELEMENT_SOFTWAREVERSION;
} else {
capwap_logging_error("Invalid configuration file, unknown application.descriptor.info.type value");
return 0;
}
desc = (struct capwap_acdescriptor_desc_subelement*)capwap_array_get_item_pointer(g_ac.descriptor.descsubelement, g_ac.descriptor.descsubelement->count);
desc->vendor = (unsigned long)configVendor;
desc->type = type;
desc->length = lengthValue;
strcpy(desc->data, configValue);
} else {
capwap_logging_error("Invalid configuration file, application.descriptor.info.value string length exceeded");
return 0;
}
} else {
capwap_logging_error("Invalid configuration file, element application.descriptor.info.value not found");
return 0;
}
} else {
capwap_logging_error("Invalid configuration file, element application.descriptor.info.type not found");
return 0;
}
} else {
capwap_logging_error("Invalid configuration file, element application.descriptor.info.idvendor not found");
return 0;
}
}
}
}
/* Set ECN of AC */
if (config_lookup_string(config, "application.ecn", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "full")) {
g_ac.dfa.ecn.flag = CAPWAP_FULL_ECN_SUPPORT;
} else if (!strcmp(configString, "limited")) {
g_ac.dfa.ecn.flag = CAPWAP_LIMITED_ECN_SUPPORT;
} else {
capwap_logging_error("Invalid configuration file, unknown application.ecn value");
return 0;
}
}
/* Set Timer of AC */
if (config_lookup_int(config, "application.timer.discovery", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt >= AC_DEFAULT_DISCOVERY_INTERVAL) && (configLongInt <= AC_MAX_DISCOVERY_INTERVAL)) {
g_ac.dfa.timers.discovery = (unsigned char)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.timer.discovery value");
return 0;
}
}
if (config_lookup_int(config, "application.timer.echorequest", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt > 0) && (configLongInt < AC_MAX_ECHO_INTERVAL)) {
g_ac.dfa.timers.echorequest = (unsigned char)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.timer.echorequest value");
return 0;
}
}
if (config_lookup_int(config, "application.timer.decrypterrorreport", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt > 0) && (configLongInt < 65536)) {
g_ac.dfa.decrypterrorreport_interval = (unsigned short)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.timer.decrypterrorreport value");
return 0;
}
}
if (config_lookup_int(config, "application.timer.idletimeout", &configLongInt) == CONFIG_TRUE) {
if (configLongInt > 0) {
g_ac.dfa.idletimeout.timeout = (unsigned long)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.timer.idletimeout value");
return 0;
}
}
/* Set wtpfallback of AC */
if (config_lookup_bool(config, "application.wtpfallback", &configInt) == CONFIG_TRUE) {
g_ac.dfa.wtpfallback.mode = ((configInt != 0) ? CAPWAP_WTP_FALLBACK_ENABLED : CAPWAP_WTP_FALLBACK_DISABLED);
}
/* Set DTLS of WTP */
if (config_lookup_bool(config, "application.dtls.enable", &configInt) == CONFIG_TRUE) {
if (configInt != 0) {
struct capwap_dtls_param dtlsparam;
/* Init dtls param */
memset(&dtlsparam, 0, sizeof(struct capwap_dtls_param));
dtlsparam.type = CAPWAP_DTLS_SERVER;
/* Set DTLS type of AC */
if (config_lookup_string(config, "application.dtls.type", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "x509")) {
dtlsparam.mode = CAPWAP_DTLS_MODE_CERTIFICATE;
} else if (!strcmp(configString, "presharedkey")) {
dtlsparam.mode = CAPWAP_DTLS_MODE_PRESHAREDKEY;
} else {
capwap_logging_error("Invalid configuration file, unknown application.dtls.type value");
return 0;
}
}
/* Set DTLS configuration of AC */
if (dtlsparam.mode == CAPWAP_DTLS_MODE_CERTIFICATE) {
if (config_lookup_string(config, "application.dtls.x509.calist", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.fileca = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.x509.certificate", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.filecert = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.x509.privatekey", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.filekey = capwap_duplicate_string(configString);
}
}
if (config_lookup_string(config, "application.dtls.x509.privatekeypassword", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
dtlsparam.cert.pwdprivatekey = capwap_duplicate_string(configString);
}
}
if (dtlsparam.cert.fileca && dtlsparam.cert.filecert && dtlsparam.cert.filekey) {
if (capwap_crypt_createcontext(&g_ac.dtlscontext, &dtlsparam)) {
g_ac.enabledtls = 1;
}
}
/* Free dtls param */
if (dtlsparam.cert.fileca) {
capwap_free(dtlsparam.cert.fileca);
}
if (dtlsparam.cert.filecert) {
capwap_free(dtlsparam.cert.filecert);
}
if (dtlsparam.cert.filekey) {
capwap_free(dtlsparam.cert.filekey);
}
if (dtlsparam.cert.pwdprivatekey) {
capwap_free(dtlsparam.cert.pwdprivatekey);
}
if (!g_ac.enabledtls) {
return 0;
}
} else if (dtlsparam.mode == CAPWAP_DTLS_MODE_PRESHAREDKEY) {
/* TODO */
}
}
}
/* Set interface binding of AC */
if (config_lookup_string(config, "application.network.binding", &configString) == CONFIG_TRUE) {
if (strlen(configString) > (IFNAMSIZ - 1)) {
capwap_logging_error("Invalid configuration file, application.network.binding string length exceeded");
return 0;
}
strcpy(g_ac.net.bind_interface, configString);
}
/* Set mtu of AC */
if (config_lookup_int(config, "application.network.mtu", &configLongInt) == CONFIG_TRUE) {
if ((configLongInt > 0) && (configLongInt < 65536)) {
g_ac.mtu = (unsigned short)configLongInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.network.mtu value");
return 0;
}
}
/* Set transport of AC */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) {
g_ac.dfa.transport.type = CAPWAP_UDP_TRANSPORT;
} else if (!strcmp(configString, "udplite")) {
g_ac.dfa.transport.type = CAPWAP_UDPLITE_TRANSPORT;
} else {
capwap_logging_error("Invalid configuration file, unknown application.network.transport value");
return 0;
}
}
/* Set ipv4 & ipv6 of AC */
if (config_lookup_bool(config, "application.network.ipv4", &configIPv4) != CONFIG_TRUE) {
configIPv4 = 1;
}
if (config_lookup_bool(config, "application.network.ipv6", &configIPv6) != CONFIG_TRUE) {
configIPv6 = 1;
}
if (configIPv4 && configIPv6) {
g_ac.net.sock_family = AF_UNSPEC;
} else if (!configIPv4 && !configIPv6) {
capwap_logging_error("Invalid configuration file, request enable application.network.ipv4 or application.network.ipv6");
return 0;
} else {
g_ac.net.sock_family = (configIPv4 ? AF_INET : AF_INET6);
}
/* Set ip dual stack of WTP */
if (config_lookup_bool(config, "application.network.ipdualstack", &configInt) == CONFIG_TRUE) {
if (!configInt) {
g_ac.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG;
g_ac.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG;
} else {
g_ac.net.bind_ctrl_flags &= ~CAPWAP_IPV6ONLY_FLAG;
g_ac.net.bind_data_flags &= ~CAPWAP_IPV6ONLY_FLAG;
}
}
return 1;
}
/* Parsing configuration */
static int ac_parsing_configuration(config_t* config) {
const char* configString;
if (config_lookup_string(config, "version", &configString) == CONFIG_TRUE) {
if (strcmp(configString, "1.0") == 0) {
return ac_parsing_configuration_1_0(config);
}
capwap_logging_error("Invalid configuration file, '%s' is not supported", configString);
} else {
capwap_logging_error("Invalid configuration file, unable to found version tag");
}
return 0;
}
/* Load configuration */
static int ac_load_configuration(int argc, char** argv) {
int c;
int result = 0;
config_t config;
ASSERT(argc >= 0);
ASSERT(argv != NULL);
/* Parsing command line */
opterr = 0;
while ((c = getopt(argc, argv, "hc:")) != -1) {
switch (c) {
case 'h': {
ac_print_usage();
return 0;
}
case 'c': {
if (strlen(optarg) < sizeof(g_configurationfile)) {
strcpy(g_configurationfile, optarg);
} else {
capwap_logging_error("Invalid -%c argument", optopt);
return -1;
}
break;
}
case '?': {
if (optopt == 'c') {
capwap_logging_error("Option -%c requires an argument", optopt);
} else {
capwap_logging_error("Unknown option character `\\x%x'", optopt);
}
ac_print_usage();
return -1;
}
}
}
/* Init libconfig */
config_init(&config);
/* Load configuration */
if (config_read_file(&config, g_configurationfile) == CONFIG_TRUE) {
result = ac_parsing_configuration(&config);
} else {
result = -1;
capwap_logging_error("Unable load the configuration file '%s': %s (%d)", g_configurationfile, config_error_text(&config), config_error_line(&config));
}
/* Free libconfig */
config_destroy(&config);
return result;
}
/* Init AC */
static int ac_configure(void) {
/* Bind to any address */
if (!capwap_bind_sockets(&g_ac.net)) {
capwap_logging_fatal("Cannot bind address");
return AC_ERROR_NETWORK;
}
return CAPWAP_SUCCESSFUL;
}
/* Close AC */
static void ac_close(void) {
ASSERT(g_ac.sessions->count == 0);
/* Close socket */
capwap_close_sockets(&g_ac.net);
}
/* Check is valid binding */
int ac_valid_binding(unsigned short binding) {
int i;
for (i = 0; i < g_ac.binding->count; i++) {
if (binding == *(unsigned short*)capwap_array_get_item_pointer(g_ac.binding, i)) {
return 1;
}
}
return 0;
}
/* Main*/
int main(int argc, char** argv) {
int value;
int result = CAPWAP_SUCCESSFUL;
/* Init logging */
capwap_logging_init();
capwap_logging_verboselevel(CAPWAP_LOGGING_ERROR);
capwap_logging_enable_console(1);
/* Init capwap */
if (geteuid() != 0) {
capwap_logging_fatal("Request root privileges");
return CAPWAP_REQUEST_ROOT;
}
/* Init random generator */
capwap_init_rand();
/* Init crypt */
if (!capwap_crypt_init()) {
capwap_logging_fatal("Error to init crypt engine");
return CAPWAP_CRYPT_ERROR;
}
/* Alloc AC */
if (!ac_init()) {
return AC_ERROR_SYSTEM_FAILER;
}
/* Read configuration file */
value = ac_load_configuration(argc, argv);
if (value < 0) {
result = AC_ERROR_LOAD_CONFIGURATION;
} else if (value > 0) {
/* Complete configuration AC */
result = ac_configure();
if (result == CAPWAP_SUCCESSFUL) {
/* Running AC */
result = ac_execute();
ac_close();
}
}
/* Free memory */
ac_destroy();
/* Free crypt */
capwap_crypt_free();
/* Check memory leak */
if (capwap_check_memory_leak(1)) {
if (result == CAPWAP_SUCCESSFUL)
result = AC_ERROR_MEMORY_LEAK;
}
/* Close logging */
capwap_logging_close();
return result;
}

117
src/ac/ac.h Normal file
View File

@ -0,0 +1,117 @@
#ifndef __CAPWAP_AC_HEADER__
#define __CAPWAP_AC_HEADER__
/* standard include */
#include "capwap.h"
#include "capwap_network.h"
#include "capwap_protocol.h"
#include "capwap_lock.h"
#include "capwap_list.h"
#include "capwap_event.h"
#include "capwap_element.h"
#include <pthread.h>
/* AC Configuration */
#define AC_DEFAULT_CONFIGURATION_FILE "/etc/capwap/ac.conf"
#define AC_DEFAULT_MAXSTATION 128
#define AC_DEFAULT_MAXSESSIONS 128
/* AC runtime error return code */
#define AC_ERROR_SYSTEM_FAILER -1000
#define AC_ERROR_LOAD_CONFIGURATION -1001
#define AC_ERROR_NETWORK -1002
#define AC_ERROR_MEMORY_LEAK 1
/* Min and max dfa values */
#define AC_MIN_WAITDTLS_INTERVAL 30
#define AC_DEFAULT_WAITDTLS_INTERVAL 60
#define AC_MIN_WAITJOIN_INTERVAL 20
#define AC_DEFAULT_WAITJOIN_INTERVAL 60
#define AC_DEFAULT_CHANGE_STATE_PENDING_TIMER 25
#define AC_MIN_DISCOVERY_INTERVAL 2
#define AC_DEFAULT_DISCOVERY_INTERVAL 20
#define AC_MAX_DISCOVERY_INTERVAL 180
#define AC_DEFAULT_ECHO_INTERVAL 30
#define AC_MAX_ECHO_INTERVAL 256
#define AC_DEFAULT_DECRYPT_ERROR_PERIOD_INTERVAL 120
#define AC_DEFAULT_IDLE_TIMEOUT_INTERVAL 300
#define AC_DEFAULT_WTP_FALLBACK_MODE CAPWAP_WTP_FALLBACK_ENABLED
#define AC_DEFAULT_DATA_CHECK_TIMER 30
#define AC_DEFAULT_RETRANSMIT_INTERVAL 3
#define AC_MAX_RETRANSMIT 5
#define AC_DEFAULT_DTLS_SESSION_DELETE 5
/* AC DFA */
struct ac_state {
/* */
struct capwap_ecnsupport_element ecn;
struct capwap_transport_element transport;
struct capwap_timers_element timers;
unsigned short decrypterrorreport_interval;
struct capwap_idletimeout_element idletimeout;
struct capwap_wtpfallback_element wtpfallback;
/* */
capwap_acipv4list_element_array* acipv4list;
capwap_acipv6list_element_array* acipv6list;
/* */
int rfcWaitJoin;
int rfcChangeStatePendingTimer;
int rfcDataCheckTimer;
int rfcDTLSSessionDelete;
/* Request retransmit */
int rfcRetransmitInterval;
int rfcRetransmitCount;
int rfcMaxRetransmit;
/* Dtls */
int rfcWaitDTLS;
};
/* Handshake DTLS Data Channel */
struct ac_data_session_handshake {
struct capwap_socket socket;
struct sockaddr_storage acaddress;
struct sockaddr_storage wtpaddress;
struct capwap_dtls dtls;
};
/* AC */
struct ac_t {
int running;
/* */
struct ac_state dfa;
struct capwap_network net;
unsigned short mtu;
struct capwap_array* binding;
struct capwap_acname_element acname;
struct capwap_acdescriptor_element descriptor;
/* Sessions */
capwap_event_t changesessionlist;
struct capwap_list* sessions;
capwap_lock_t sessionslock;
struct capwap_list* datasessionshandshake;
/* Dtls */
int enabledtls;
struct capwap_dtls_context dtlscontext;
};
extern struct ac_t g_ac;
/* Primary thread */
int ac_execute(void);
int ac_valid_binding(unsigned short binding);
void ac_update_statistics(void);
#endif /* __CAPWAP_AC_HEADER__ */

128
src/ac/ac_dfa_configure.c Normal file
View File

@ -0,0 +1,128 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_configure(struct ac_session_t* session, struct capwap_packet* packet) {
unsigned long i;
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
struct capwap_build_packet* buildpacket;
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
if (!capwap_build_packet_validate(buildpacket, NULL)) {
unsigned short binding;
/* */
binding = GET_WBID_HEADER(&buildpacket->header);
if (ac_valid_binding(binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_CONFIGURATION_STATUS_REQUEST) && IS_SEQUENCE_SMALLER(session->remoteseqnumber, buildpacket->ctrlmsg.seq)) {
struct capwap_element_configurationstatus_request configurationstatusrequest;
/* Configuration Status request info*/
capwap_init_element_configurationstatus_request(&configurationstatusrequest, binding);
/* Parsing elements list */
if (capwap_parsing_element_configurationstatus_request(&configurationstatusrequest, buildpacket->elementslist->first)) {
struct capwap_build_packet* responsepacket;
/* TODO: gestione richiesta */
/* Create response */
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
responsepacket->isctrlmsg = 1;
/* Prepare configuration status response */
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_CONFIGURATION_STATUS_RESPONSE, buildpacket->ctrlmsg.seq);
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_TIMERS_ELEMENT(&session->dfa.timers));
for (i = 0; i < configurationstatusrequest.radioadmstatus->count; i++) {
struct capwap_decrypterrorreportperiod_element report;
struct capwap_radioadmstate_element* radioadm = (struct capwap_radioadmstate_element*)capwap_array_get_item_pointer(configurationstatusrequest.radioadmstatus, i);
report.radioid = radioadm->radioid;
report.interval = session->dfa.decrypterrorreport_interval;
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_DECRYPTERRORREPORTPERIOD_ELEMENT(&report));
}
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_IDLETIMEOUT_ELEMENT(&session->dfa.idletimeout));
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_WTPFALLBACK_ELEMENT(&session->dfa.wtpfallback));
if (session->dfa.acipv4list->count > 0) {
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACIPV4LIST_ELEMENT(session->dfa.acipv4list));
}
if (session->dfa.acipv6list->count > 0) {
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACIPV6LIST_ELEMENT(session->dfa.acipv6list));
}
/* CAPWAP_CREATE_RADIOOPRSTATE_ELEMENT */ /* TODO */
/* CAPWAP_CREATE_WTPSTATICIPADDRESS_ELEMENT */ /* TODO */
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
if (!capwap_build_packet_validate(responsepacket, NULL)) {
int result;
/* Free old reference for this request */
ac_free_reference_last_response(session);
/* Send configuration status response to WTP */
result = capwap_fragment_build_packet(responsepacket, session->responsefragmentpacket, session->mtu, session->fragmentid);
if (result >= 0) {
if (result == 1) {
session->fragmentid++;
}
/* Save remote sequence number */
session->remoteseqnumber = buildpacket->ctrlmsg.seq;
capwap_get_packet_digest((void*)packet->header, packet->packetsize, session->lastrecvpackethash);
/* Send */
for (i = 0; i < session->responsefragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->responsefragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send configuration status response packet");
break;
}
}
/* Change status */
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_STATE);
capwap_set_timeout(session->dfa.rfcChangeStatePendingTimer, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
}
} else {
capwap_logging_debug("Warning: build invalid configuration status response packet");
}
/* Free memory */
capwap_build_packet_free(responsepacket);
}
/* Free */
capwap_free_element_configurationstatus_request(&configurationstatusrequest, binding);
}
}
/* Free */
capwap_build_packet_free(buildpacket);
}
} else {
/* Configure timeout */
ac_dfa_change_state(session, CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_configure_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

169
src/ac/ac_dfa_datacheck.c Normal file
View File

@ -0,0 +1,169 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_packet* packet) {
unsigned long i;
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
struct capwap_build_packet* buildpacket;
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
if (!capwap_build_packet_validate(buildpacket, NULL)) {
unsigned short binding;
/* */
binding = GET_WBID_HEADER(&buildpacket->header);
if (ac_valid_binding(binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_CHANGE_STATE_EVENT_REQUEST) && IS_SEQUENCE_SMALLER(session->remoteseqnumber, buildpacket->ctrlmsg.seq)) {
struct capwap_element_changestateevent_request changeeventrequest;
/* Change event request info */
capwap_init_element_changestateevent_request(&changeeventrequest, binding);
/* Parsing elements list */
if (capwap_parsing_element_changestateevent_request(&changeeventrequest, buildpacket->elementslist->first)) {
struct capwap_build_packet* responsepacket;
/* TODO: gestione richiesta */
/* Create response */
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
responsepacket->isctrlmsg = 1;
/* Prepare change event response */
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_CHANGE_STATE_EVENT_RESPONSE, buildpacket->ctrlmsg.seq);
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
if (!capwap_build_packet_validate(responsepacket, NULL)) {
int result;
/* Free old reference for this request */
ac_free_reference_last_response(session);
/* Send change event response to WTP */
result = capwap_fragment_build_packet(responsepacket, session->responsefragmentpacket, session->mtu, session->fragmentid);
if (result >= 0) {
if (result == 1) {
session->fragmentid++;
}
/* Save remote sequence number */
session->remoteseqnumber = buildpacket->ctrlmsg.seq;
capwap_get_packet_digest((void*)packet->header, packet->packetsize, session->lastrecvpackethash);
/* Send */
for (i = 0; i < session->responsefragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->responsefragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send change event response packet");
break;
}
}
/* Change status */
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_RUN_STATE);
capwap_set_timeout(session->dfa.rfcDataCheckTimer, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
}
} else {
capwap_logging_debug("Warning: build invalid configuration status response packet");
}
/* Free memory */
capwap_build_packet_free(responsepacket);
}
/* Free */
capwap_free_element_changestateevent_request(&changeeventrequest, binding);
}
}
/* Free */
capwap_build_packet_free(buildpacket);
}
} else {
/* Configure timeout */
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
/* Wait Data Channel Keep-Alive packet */
if (!packet->socket.isctrlsocket) {
struct capwap_build_packet* buildpacket;
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
struct capwap_sessionid_element sessionid;
if (capwap_get_sessionid_from_keepalive(buildpacket, &sessionid)) {
if (!memcmp(&sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
int result;
capwap_fragment_packet_array* txfragpacket;
/* Receive data packet keepalive, response with same packet */
txfragpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
result = capwap_fragment_build_packet(buildpacket, txfragpacket, CAPWAP_DONT_FRAGMENT, 0);
if (!result) {
struct capwap_packet* txpacket;
ASSERT(txfragpacket->count == 1);
txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(txfragpacket, 0);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->datadtls, session->datasocket.socket[session->datasocket.type], txpacket->header, txpacket->packetsize, &session->acdataaddress, &session->wtpdataaddress)) {
capwap_logging_debug("Warning: error to send data channel keepalive packet");
result = -1;
}
}
/* */
capwap_fragment_free(txfragpacket);
capwap_array_free(txfragpacket);
if (!result) {
/* Capwap handshake complete */
ac_dfa_change_state(session, CAPWAP_RUN_STATE);
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
} else {
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
}
}
/* Free */
capwap_build_packet_free(buildpacket);
}
}
} else {
/* Configure timeout */
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_datacheck_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

51
src/ac/ac_dfa_dtls.c Normal file
View File

@ -0,0 +1,51 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* DTLS BIO send */
int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_session_t* session = (struct ac_session_t*)param;
struct capwap_socket* socket = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->ctrlsocket : &session->datasocket);
struct sockaddr_storage* wtpaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->wtpctrladdress : &session->wtpdataaddress);
struct sockaddr_storage* acaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &session->acctrladdress : &session->acdataaddress);
return capwap_sendto(socket->socket[socket->type], buffer, length, acaddress, wtpaddress);
}
/* */
int ac_dfa_state_dtlssetup(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
ASSERT(packet == NULL);
/* Create DTLS session */
if (!capwap_crypt_createsession(&session->ctrldtls, CAPWAP_DTLS_CONTROL_SESSION, &g_ac.dtlscontext, ac_bio_send, session)) {
ac_dfa_change_state(session, CAPWAP_DTLS_SETUP_TO_IDLE_STATE); /* TODO */
status = AC_DFA_NO_PACKET;
} else {
if (capwap_crypt_open(&session->ctrldtls, &session->wtpctrladdress) == CAPWAP_HANDSHAKE_ERROR) {
ac_dfa_change_state(session, CAPWAP_DTLS_SETUP_TO_IDLE_STATE); /* TODO */
status = AC_DFA_NO_PACKET;
} else {
ac_dfa_change_state(session, CAPWAP_DTLS_CONNECT_STATE);
}
}
return status;
}
/* */
int ac_dfa_state_dtlsconnect(struct ac_session_t* session, struct capwap_packet* packet) {
ASSERT(session != NULL);
ASSERT(packet == NULL);
ac_dfa_change_state(session, CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE); /* TODO */
return AC_DFA_NO_PACKET;
}
/* */
int ac_dfa_state_dtlsconnect_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

18
src/ac/ac_dfa_imagedata.c Normal file
View File

@ -0,0 +1,18 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_imagedata(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
/* TODO */
return status;
}
/* */
int ac_dfa_state_imagedata_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

272
src/ac/ac_dfa_join.c Normal file
View File

@ -0,0 +1,272 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_join(struct ac_session_t* session, struct capwap_packet* packet) {
int i;
int status = AC_DFA_ACCEPT_PACKET;
struct capwap_resultcode_element resultcode = { CAPWAP_RESULTCODE_FAILURE };
struct capwap_build_packet* responsepacket;
ASSERT(session != NULL);
if (packet) {
struct capwap_build_packet* buildpacket;
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
int validpacket;
unsigned long checkpacket;
struct capwap_array* returnedmessagearray = NULL;
capwap_unrecognized_element_array* unrecognizedarray;
struct capwap_element_join_request joinrequest;
unsigned short binding = GET_WBID_HEADER(&buildpacket->header);
/* */
unrecognizedarray = capwap_array_create(sizeof(struct unrecognized_info), 0);
/* */
checkpacket = capwap_build_packet_validate(buildpacket, unrecognizedarray);
if (!checkpacket) {
if (ac_valid_binding(binding)) {
if (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_JOIN_REQUEST) {
resultcode.code = CAPWAP_RESULTCODE_SUCCESS;
} else {
resultcode.code = CAPWAP_RESULTCODE_MSG_UNEXPECTED_INVALID_CURRENT_STATE;
}
} else {
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_BINDING_NOT_SUPPORTED;
}
} else {
if ((checkpacket & CAPWAP_MISSING_MANDATORY_MSG_ELEMENT) != 0) {
resultcode.code = CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT;
} else if ((checkpacket & CAPWAP_UNRECOGNIZED_MSG_ELEMENT) != 0) {
struct capwap_list_item* itemelement;
resultcode.code = CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT;
returnedmessagearray = capwap_array_create(sizeof(struct capwap_returnedmessage_element), unrecognizedarray->count);
for (i = 0; i < unrecognizedarray->count; i++) {
struct unrecognized_info* reasoninfo = capwap_array_get_item_pointer(unrecognizedarray, i);
/* Search element */
itemelement = buildpacket->elementslist->first;
while (itemelement != NULL) {
struct capwap_message_element* elementitem = (struct capwap_message_element*)itemelement->item;
if (ntohs(elementitem->type) == reasoninfo->element) {
struct capwap_returnedmessage_element* returnedelement = capwap_array_get_item_pointer(returnedmessagearray, i);
unsigned short length = sizeof(struct capwap_message_element) + ntohs(elementitem->length);
returnedelement->reason = reasoninfo->reason;
returnedelement->length = min(length, CAPWAP_RETURNED_MESSAGE_MAX_LENGTH);
memcpy(&returnedelement->message[0], elementitem, returnedelement->length);
break;
}
/* Next */
itemelement = itemelement->next;
}
}
}
}
/* */
capwap_array_free(unrecognizedarray);
/* */
capwap_init_element_join_request(&joinrequest, binding);
if (resultcode.code == CAPWAP_RESULTCODE_SUCCESS) {
/* Parsing elements list */
if (capwap_parsing_element_join_request(&joinrequest, buildpacket->elementslist->first)) {
/* TODO: gestione richiesta */
/* Get sessionid */
memcpy(&session->sessionid, joinrequest.sessionid, sizeof(struct capwap_sessionid_element));
/* Get binding */
session->binding = binding;
resultcode.code = CAPWAP_RESULTCODE_SUCCESS;
}
}
/* Create response */
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
responsepacket->isctrlmsg = 1;
/* Prepare join response */
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_JOIN_RESPONSE, buildpacket->ctrlmsg.seq);
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_RESULTCODE_ELEMENT(&resultcode));
/* Check is valid packet after parsing request */
validpacket = (((resultcode.code == CAPWAP_RESULTCODE_SUCCESS) || (resultcode.code == CAPWAP_RESULTCODE_SUCCESS_NAT_DETECTED)) ? 1 : 0);
if (validpacket) {
struct capwap_list* controllist;
struct capwap_list_item* item;
/* Update statistics */
ac_update_statistics();
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACDESCRIPTOR_ELEMENT(&g_ac.descriptor));
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACNAME_ELEMENT(&g_ac.acname));
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
for (i = 0; i < joinrequest.binding.ieee80211.wtpradioinformation->count; i++) {
struct capwap_80211_wtpradioinformation_element* radio;
radio = (struct capwap_80211_wtpradioinformation_element*)capwap_array_get_item_pointer(joinrequest.binding.ieee80211.wtpradioinformation, i);
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(radio));
}
} else {
capwap_logging_debug("Unknown capwap binding");
}
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ECNSUPPORT_ELEMENT(&session->dfa.ecn));
/* Get information from any local address */
controllist = capwap_list_create();
ac_get_control_information(controllist);
for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) {
struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV4_ELEMENT(&element));
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) {
struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
element.wtpcount = sessioncontrol->count;
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV6_ELEMENT(&element));
}
}
capwap_list_free(controllist);
if (session->acctrladdress.ss_family == AF_INET) {
struct capwap_localipv4_element addr;
memcpy(&addr.address, &((struct sockaddr_in*)&session->acctrladdress)->sin_addr, sizeof(struct in_addr));
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_LOCALIPV4_ELEMENT(&addr));
} else if (session->acctrladdress.ss_family == AF_INET6) {
struct capwap_localipv6_element addr;
memcpy(&addr.address, &((struct sockaddr_in6*)&session->acctrladdress)->sin6_addr, sizeof(struct in6_addr));
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_LOCALIPV6_ELEMENT(&addr));
}
/* CAPWAP_CREATE_ACIPV4LIST_ELEMENT */ /* TODO */
/* CAPWAP_CREATE_ACIPV6LIST_ELEMENT */ /* TODO */
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_TRANSPORT_ELEMENT(&session->dfa.transport));
/* CAPWAP_CREATE_IMAGEIDENTIFIER_ELEMENT */ /* TODO */
/* CAPWAP_CREATE_MAXIMUMMESSAGELENGTH_ELEMENT */ /* TODO */
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
} else if (resultcode.code == CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT) {
ASSERT(returnedmessagearray != NULL);
for (i = 0; i < returnedmessagearray->count; i++) {
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_RETURNEDMESSAGE_ELEMENT(capwap_array_get_item_pointer(returnedmessagearray, i)));
}
capwap_array_free(returnedmessagearray);
}
/* Validate packet */
if (!validpacket || !capwap_build_packet_validate(responsepacket, NULL)) {
int result;
/* Free old reference for this request */
ac_free_reference_last_response(session);
/* Send join response to WTP */
result = capwap_fragment_build_packet(responsepacket, session->responsefragmentpacket, session->mtu, session->fragmentid);
if (result >= 0) {
if (result == 1) {
session->fragmentid++;
}
/* Save remote sequence number */
session->remoteseqnumber = buildpacket->ctrlmsg.seq;
capwap_get_packet_digest((void*)packet->header, packet->packetsize, session->lastrecvpackethash);
/* Send */
for (i = 0; i < session->responsefragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->responsefragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send join response packet");
break;
}
}
}
} else {
capwap_logging_debug("Warning: build invalid join response packet");
}
/* Free memory */
capwap_build_packet_free(responsepacket);
capwap_free_element_join_request(&joinrequest, binding);
capwap_build_packet_free(buildpacket);
/* Change state */
if (validpacket) {
ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE);
} else {
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
}
} else {
/* Join timeout */
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
unsigned short lengthpayload;
lengthpayload = packet->packetsize - GET_HLEN_HEADER(packet->header) * 4;
if (lengthpayload >= sizeof(struct capwap_control_message)) {
struct capwap_control_message* ctrlmsg = (struct capwap_control_message*)packet->payload;
unsigned long type = ntohl(ctrlmsg->type);
if (type == CAPWAP_CONFIGURATION_STATUS_REQUEST) {
ac_dfa_change_state(session, CAPWAP_CONFIGURE_STATE);
status = ac_dfa_state_configure(session, packet);
} else if (type == CAPWAP_IMAGE_DATA_REQUEST) {
ac_dfa_change_state(session, CAPWAP_IMAGE_DATA_STATE);
status = ac_dfa_state_imagedata(session, packet);
}
}
} else {
/* Join timeout */
ac_dfa_change_state(session, CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_join_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

81
src/ac/ac_dfa_reset.c Normal file
View File

@ -0,0 +1,81 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_reset(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
if (!capwap_compare_ip(&session->wtpctrladdress, &packet->remoteaddr)) {
struct capwap_build_packet* buildpacket;
/* Parsing packet */
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
if (!capwap_build_packet_validate(buildpacket, NULL)) {
unsigned short binding;
/* */
binding = GET_WBID_HEADER(&buildpacket->header);
if ((binding == session->binding) && (ntohl(buildpacket->ctrlmsg.type) == CAPWAP_RESET_RESPONSE) && ((session->localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
struct capwap_element_reset_response resetresponse;
/* Valid packet, free request packet */
ac_free_reference_last_request(session);
/* Configuration status response info */
capwap_init_element_reset_response(&resetresponse, binding);
/* Parsing elements list */
if (capwap_parsing_element_reset_response(&resetresponse, buildpacket->elementslist->first)) {
ac_dfa_change_state(session, CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
/* Free join response */
capwap_free_element_reset_response(&resetresponse, binding);
}
}
/* Free */
capwap_build_packet_free(buildpacket);
}
}
} else {
int i;
/* No Configuration status response received */
session->dfa.rfcRetransmitCount++;
if (session->dfa.rfcRetransmitCount >= session->dfa.rfcMaxRetransmit) {
/* Timeout join state */
ac_free_reference_last_request(session);
ac_dfa_change_state(session, CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
} else {
/* Retransmit configuration request */
for (i = 0; i < session->requestfragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->requestfragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
capwap_logging_debug("Warning: error to send configuration status request packet");
break;
}
}
/* Update timeout */
capwap_set_timeout(session->dfa.rfcRetransmitInterval, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
}
}
return status;
}
/* */
int ac_dfa_state_reset_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

263
src/ac/ac_dfa_run.c Normal file
View File

@ -0,0 +1,263 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
static int receive_echo_request(struct ac_session_t* session, struct capwap_build_packet* buildpacket, struct capwap_packet* packet) {
unsigned long i;
unsigned short binding;
ASSERT(session != NULL);
ASSERT(buildpacket != NULL);
ASSERT(packet != NULL);
/* */
binding = GET_WBID_HEADER(&buildpacket->header);
if (ac_valid_binding(binding) && IS_SEQUENCE_SMALLER(session->remoteseqnumber, buildpacket->ctrlmsg.seq)) {
struct capwap_element_echo_request echorequest;
/* Echo request info*/
capwap_init_element_echo_request(&echorequest, binding);
/* Parsing elements list */
if (capwap_parsing_element_echo_request(&echorequest, buildpacket->elementslist->first)) {
struct capwap_build_packet* responsepacket;
/* Create response */
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
responsepacket->isctrlmsg = 1;
/* Prepare echo response */
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_ECHO_RESPONSE, buildpacket->ctrlmsg.seq);
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
if (!capwap_build_packet_validate(responsepacket, NULL)) {
int result;
/* Free old reference for this request */
ac_free_reference_last_response(session);
/* Send echo response to WTP */
result = capwap_fragment_build_packet(responsepacket, session->responsefragmentpacket, session->mtu, session->fragmentid);
if (result >= 0) {
if (result == 1) {
session->fragmentid++;
}
/* Save remote sequence number */
session->remoteseqnumber = buildpacket->ctrlmsg.seq;
capwap_get_packet_digest((void*)packet->header, packet->packetsize, session->lastrecvpackethash);
/* Send */
for (i = 0; i < session->responsefragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->responsefragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send echo response packet");
break;
}
}
}
}
/* Free memory */
capwap_build_packet_free(responsepacket);
}
/* Free */
capwap_free_element_echo_request(&echorequest, binding);
}
return 0;
}
/* */
int ac_dfa_state_run(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
if (packet) {
struct capwap_build_packet* buildpacket;
buildpacket = capwap_rx_packet_create((void*)packet->header, packet->packetsize, packet->socket.isctrlsocket);
if (buildpacket) {
if (!capwap_build_packet_validate(buildpacket, NULL)) {
if (packet->socket.isctrlsocket) {
unsigned long typemsg = ntohl(buildpacket->ctrlmsg.type);
if (capwap_is_request_type(typemsg) || ((session->localseqnumber - 1) == buildpacket->ctrlmsg.seq)) {
switch (typemsg) {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
case CAPWAP_ECHO_REQUEST: {
if (!receive_echo_request(session, buildpacket, packet)) {
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
} else {
ac_dfa_change_state(session, CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
/* TODO */
capwap_set_timeout(AC_MAX_ECHO_INTERVAL, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
break;
}
}
}
} else {
if (IS_FLAG_K_HEADER(&buildpacket->header)) {
struct capwap_sessionid_element sessionid;
if (capwap_get_sessionid_from_keepalive(buildpacket, &sessionid)) {
if (!memcmp(&sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
int result;
capwap_fragment_packet_array* txfragpacket;
/* Receive data packet keepalive, response with same packet */
txfragpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
result = capwap_fragment_build_packet(buildpacket, txfragpacket, CAPWAP_DONT_FRAGMENT, 0);
if (!result) {
struct capwap_packet* txpacket;
ASSERT(txfragpacket->count == 1);
txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(txfragpacket, 0);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->datadtls, session->datasocket.socket[session->datasocket.type], txpacket->header, txpacket->packetsize, &session->acdataaddress, &session->wtpdataaddress)) {
capwap_logging_debug("Warning: error to send data channel keepalive packet");
result = -1;
}
}
/* */
capwap_fragment_free(txfragpacket);
capwap_array_free(txfragpacket);
if (result) {
ac_dfa_change_state(session, CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
}
}
} else {
/* TODO */
}
}
}
/* Free */
capwap_build_packet_free(buildpacket);
}
} else {
ac_dfa_change_state(session, CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE);
status = AC_DFA_NO_PACKET;
}
return status;
}
/* */
int ac_dfa_state_run_to_reset(struct ac_session_t* session, struct capwap_packet* packet) {
int status = AC_DFA_NO_PACKET;
struct capwap_build_packet* buildpacket;
ASSERT(session != NULL);
ASSERT(packet == NULL);
/* Build packet */
buildpacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, session->binding);
buildpacket->isctrlmsg = 1;
/* Prepare reset request */
capwap_build_packet_set_control_message_type(buildpacket, CAPWAP_RESET_REQUEST, session->localseqnumber++);
capwap_build_packet_add_message_element(buildpacket, CAPWAP_CREATE_IMAGEIDENTIFIER_ELEMENT(&session->startupimage));
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
if (!capwap_build_packet_validate(buildpacket, NULL)) {
int i;
int result;
/* Free old reference for this request */
ac_free_reference_last_request(session);
/* Send reset request to WTP */
result = capwap_fragment_build_packet(buildpacket, session->requestfragmentpacket, session->mtu, session->fragmentid);
if (result >= 0) {
if (result == 1) {
session->fragmentid++;
}
/* Send */
for (i = 0; i < session->requestfragmentpacket->count; i++) {
struct capwap_packet* txpacket = (struct capwap_packet*)capwap_array_get_item_pointer(session->requestfragmentpacket, i);
ASSERT(txpacket != NULL);
if (!capwap_crypt_sendto(&session->ctrldtls, session->ctrlsocket.socket[session->ctrlsocket.type], txpacket->header, txpacket->packetsize, &session->acctrladdress, &session->wtpctrladdress)) {
capwap_logging_debug("Warning: error to send reset request packet");
result = -1;
break;
}
}
}
if (result == -1) {
/* Error to send packets */
ac_free_reference_last_request(session);
ac_dfa_change_state(session, CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE);
} else {
session->dfa.rfcRetransmitCount = 0;
capwap_killall_timeout(&session->timeout);
capwap_set_timeout(session->dfa.rfcRetransmitInterval, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
ac_dfa_change_state(session, CAPWAP_RESET_STATE);
status = AC_DFA_ACCEPT_PACKET;
}
}
/* Free memory */
capwap_build_packet_free(buildpacket);
return status;
}
/* */
int ac_dfa_state_run_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet) {
return ac_session_teardown_connection(session);
}

22
src/ac/ac_dfa_teardown.c Normal file
View File

@ -0,0 +1,22 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_array.h"
#include "ac_session.h"
/* */
int ac_dfa_state_teardown(struct ac_session_t* session, struct capwap_packet* packet) {
ASSERT(session != NULL);
ASSERT(packet == NULL);
/* Defered free resource */
ac_dfa_change_state(session, CAPWAP_DEAD_STATE);
return AC_DFA_DROP_PACKET;
}
/* */
int ac_dfa_state_dead(struct ac_session_t* session, struct capwap_packet* packet) {
ASSERT(session != NULL);
ASSERT(packet == NULL);
return AC_DFA_DEAD;
}

276
src/ac/ac_discovery.c Normal file
View File

@ -0,0 +1,276 @@
#include "ac.h"
#include "capwap_protocol.h"
#include "ac_discovery.h"
#include "ac_session.h"
#define AC_DISCOVERY_CLEANUP_TIMEOUT 1000
struct ac_discovery_t {
pthread_t threadid;
int endthread;
unsigned short fragmentid;
unsigned char txseqnumber;
capwap_event_t waitpacket;
capwap_lock_t packetslock;
struct capwap_list* packets;
};
struct ac_discovery_packet {
int sendsock;
struct sockaddr_storage sender;
char data[0];
};
static struct ac_discovery_t g_ac_discovery;
/* */
int ac_discovery_start(void) {
int result;
memset(&g_ac_discovery, 0, sizeof(struct ac_discovery_t));
/* Init */
capwap_event_init(&g_ac_discovery.waitpacket);
capwap_lock_init(&g_ac_discovery.packetslock);
g_ac_discovery.packets = capwap_list_create();
/* Create thread */
result = pthread_create(&g_ac_discovery.threadid, NULL, ac_discovery_thread, NULL);
if (result) {
capwap_logging_debug("Unable create discovery thread");
return 0;
}
return 1;
}
/* */
void ac_discovery_stop(void) {
void* dummy;
g_ac_discovery.endthread = 1;
capwap_event_signal(&g_ac_discovery.waitpacket);
pthread_join(g_ac_discovery.threadid, &dummy);
/* Free memory */
capwap_event_destroy(&g_ac_discovery.waitpacket);
capwap_lock_exit(&g_ac_discovery.packetslock);
capwap_list_free(g_ac_discovery.packets);
}
/* */
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender) {
struct capwap_list_item* item;
struct ac_discovery_packet* packet;
ASSERT(buffer != NULL);
ASSERT(buffersize > 0);
ASSERT(sock >= 0);
ASSERT(sender != NULL);
/* TODO: mettere un history delle discovery request già processate per non eseguirle di nuovo */
/* L'elemento deve rimanere per la durata minima di una discovery request */
/* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize);
packet = (struct ac_discovery_packet*)item->item;
packet->sendsock = sock;
memcpy(&packet->sender, sender, sizeof(struct sockaddr_storage));
memcpy(packet->data, buffer, buffersize);
/* Append to packets list */
capwap_lock_enter(&g_ac_discovery.packetslock);
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
capwap_event_signal(&g_ac_discovery.waitpacket);
capwap_lock_exit(&g_ac_discovery.packetslock);
}
/* */
static struct capwap_build_packet* ac_create_discovery_response(struct capwap_build_packet* packet, struct capwap_element_discovery_request* discoveryrequest, struct sockaddr_storage* sender) {
int i;
unsigned short binding;
struct capwap_list* controllist;
struct capwap_list_item* item;
struct capwap_build_packet* responsepacket;
ASSERT(packet != NULL);
ASSERT(discoveryrequest != NULL);
ASSERT(sender != NULL);
/* Check is valid binding */
binding = GET_WBID_HEADER(&packet->header);
if (!ac_valid_binding(binding)) {
return NULL;
}
/* Build packet */
responsepacket = capwap_tx_packet_create(CAPWAP_RADIOID_NONE, binding);
responsepacket->isctrlmsg = 1;
/* Update statistics */
ac_update_statistics();
/* Prepare discovery response */
capwap_build_packet_set_control_message_type(responsepacket, CAPWAP_DISCOVERY_RESPONSE, packet->ctrlmsg.seq);
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACDESCRIPTOR_ELEMENT(&g_ac.descriptor));
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_ACNAME_ELEMENT(&g_ac.acname));
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
for (i = 0; i < discoveryrequest->binding.ieee80211.wtpradioinformation->count; i++) {
struct capwap_80211_wtpradioinformation_element* radio;
radio = (struct capwap_80211_wtpradioinformation_element*)capwap_array_get_item_pointer(discoveryrequest->binding.ieee80211.wtpradioinformation, i);
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(radio));
}
} else {
capwap_logging_debug("Unknown capwap binding");
}
/* Get information from any local address */
controllist = capwap_list_create();
ac_get_control_information(controllist);
for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) {
struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV4_ELEMENT(&element));
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) {
struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
element.wtpcount = sessioncontrol->count;
capwap_build_packet_add_message_element(responsepacket, CAPWAP_CREATE_CONTROLIPV6_ELEMENT(&element));
}
}
capwap_list_free(controllist);
/* CAPWAP_CREATE_VENDORSPECIFICPAYLOAD_ELEMENT */ /* TODO */
return responsepacket;
}
/* Cleanup info discovery */
static void ac_discovery_cleanup(void) {
/* Clean history discovery request */
/* TODO */
}
/* */
static void ac_discovery_run(void) {
int sizedata;
struct capwap_list_item* itempacket;
struct capwap_build_packet* buildpacket;
struct ac_discovery_packet* packet;
unsigned short binding;
while (!g_ac_discovery.endthread) {
/* Get packet */
capwap_lock_enter(&g_ac_discovery.packetslock);
itempacket = NULL;
if (g_ac_discovery.packets->count > 0) {
itempacket = capwap_itemlist_remove_head(g_ac_discovery.packets);
}
capwap_lock_exit(&g_ac_discovery.packetslock);
if (!itempacket) {
/* Wait packet with timeout*/
if (!capwap_event_wait_timeout(&g_ac_discovery.waitpacket, AC_DISCOVERY_CLEANUP_TIMEOUT)) {
ac_discovery_cleanup();
}
continue;
}
/* */
packet = (struct ac_discovery_packet*)itempacket->item;
sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet);
/* Parsing packet */
buildpacket = capwap_rx_packet_create(packet->data, sizedata, 1);
if (buildpacket) {
if (!capwap_build_packet_validate(buildpacket, NULL)) {
struct capwap_element_discovery_request discoveryrequest;
/* */
binding = GET_WBID_HEADER(&buildpacket->header);
capwap_init_element_discovery_request(&discoveryrequest, binding);
/* Parsing elements list */
if (capwap_parsing_element_discovery_request(&discoveryrequest, buildpacket->elementslist->first)) {
struct capwap_build_packet* txpacket;
capwap_fragment_packet_array* responsefragmentpacket = NULL;
/* Creare discovery response */
txpacket = ac_create_discovery_response(buildpacket, &discoveryrequest, &packet->sender);
if (txpacket) {
int result = -1;
if (!capwap_build_packet_validate(txpacket, NULL)) {
responsefragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
result = capwap_fragment_build_packet(txpacket, responsefragmentpacket, g_ac.mtu, g_ac_discovery.fragmentid);
if (result == 1) {
g_ac_discovery.fragmentid++;
}
} else {
capwap_logging_debug("Warning: build invalid discovery response packet");
}
capwap_build_packet_free(txpacket);
/* Send discovery response to WTP */
if (result >= 0) {
int i;
for (i = 0; i < responsefragmentpacket->count; i++) {
struct capwap_packet* sendpacket = (struct capwap_packet*)capwap_array_get_item_pointer(responsefragmentpacket, i);
ASSERT(sendpacket != NULL);
if (!capwap_sendto(packet->sendsock, sendpacket->header, sendpacket->packetsize, NULL, &packet->sender)) {
capwap_logging_debug("Warning: error to send discovery response packet");
break;
}
}
}
}
/* Don't buffering a packets sent */
if (responsefragmentpacket) {
capwap_fragment_free(responsefragmentpacket);
capwap_array_free(responsefragmentpacket);
}
}
/* Free discovery request */
capwap_free_element_discovery_request(&discoveryrequest, binding);
}
/* */
capwap_build_packet_free(buildpacket);
}
/* Free packet */
capwap_itemlist_free(itempacket);
}
}
/* */
void* ac_discovery_thread(void* param) {
capwap_logging_debug("Discovery start");
ac_discovery_run();
capwap_logging_debug("Discovery stop");
/* Thread exit */
pthread_exit(NULL);
return NULL;
}

10
src/ac/ac_discovery.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __AC_DISCOVERY_HEADER__
#define __AC_DISCOVERY_HEADER__
void* ac_discovery_thread(void* param);
int ac_discovery_start(void);
void ac_discovery_stop(void);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender);
#endif /* __AC_DISCOVERY_HEADER__ */

532
src/ac/ac_execute.c Normal file
View File

@ -0,0 +1,532 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "capwap_event.h"
#include "ac_session.h"
#include "ac_discovery.h"
#include <signal.h>
/* Add packet to session */
static void ac_session_add_packet(struct ac_session_t* session, char* buffer, int size, int isctrlsocket, int plainbuffer) {
struct capwap_list_item* item;
struct ac_packet* packet;
ASSERT(session != NULL);
ASSERT(buffer != NULL);
ASSERT(size > 0);
/* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_packet) + size);
packet = (struct ac_packet*)item->item;
packet->plainbuffer = plainbuffer;
memcpy(packet->buffer, buffer, size);
/* Append to packets list */
capwap_lock_enter(&session->packetslock);
capwap_itemlist_insert_after((isctrlsocket ? session->controlpackets : session->datapackets), NULL, item);
capwap_event_signal(&session->waitpacket);
capwap_lock_exit(&session->packetslock);
}
/* Find AC sessions */
static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_storage* address, int isctrlsocket) {
struct ac_session_t* result = NULL;
struct capwap_list_item* search;
ASSERT(address != NULL);
capwap_lock_enter(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!capwap_compare_ip(address, (isctrlsocket ? &session->wtpctrladdress : &session->wtpdataaddress))) {
session->count++;
result = session;
break;
}
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
return result;
}
/* */
static struct ac_session_t* ac_get_session_from_keepalive(void* buffer, int buffersize) {
struct ac_session_t* result = NULL;
struct capwap_build_packet* buildpacket;
ASSERT(buffer != NULL);
ASSERT(buffersize > 0);
buildpacket = capwap_rx_packet_create(buffer, buffersize, 0);
if (buildpacket) {
struct capwap_sessionid_element sessionid;
if (capwap_get_sessionid_from_keepalive(buildpacket, &sessionid)) {
struct capwap_list_item* search;
capwap_lock_enter(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
if (!memcmp(&sessionid, &session->sessionid, sizeof(struct capwap_sessionid_element))) {
session->count++;
result = session;
break;
}
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
}
/* Free */
capwap_build_packet_free(buildpacket);
}
return result;
}
/* Close session */
static void ac_close_session(struct ac_session_t* session) {
session->closesession = 1;
capwap_event_signal(&session->waitpacket);
}
/* Close sessions */
static void ac_close_sessions() {
struct capwap_list_item* search;
capwap_lock_enter(&g_ac.sessionslock);
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL);
ac_close_session(session);
search = search->next;
}
capwap_lock_exit(&g_ac.sessionslock);
}
/* DTLS Handshake BIO send */
static int ac_bio_handshake_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_data_session_handshake* handshake = (struct ac_data_session_handshake*)param;
return capwap_sendto(handshake->socket.socket[handshake->socket.type], buffer, length, &handshake->acaddress, &handshake->wtpaddress);
}
/* Find AC sessions */
static void ac_update_session_from_datapacket(struct capwap_socket* socket, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, void* buffer, int buffersize) {
struct ac_session_t* session = NULL;
struct capwap_preamble* preamble = (struct capwap_preamble*)buffer;
ASSERT(buffer != NULL);
ASSERT(buffersize > sizeof(struct capwap_preamble));
ASSERT(socket != NULL);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
/* */
if (preamble->type == CAPWAP_PREAMBLE_HEADER) {
if ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED) != 0) {
session = ac_get_session_from_keepalive(buffer, buffersize);
if (session) {
/* Update data session */
memcpy(&session->datasocket, socket, sizeof(struct capwap_socket));
memcpy(&session->acdataaddress, recvtoaddr, sizeof(struct sockaddr_storage));
memcpy(&session->wtpdataaddress, recvfromaddr, sizeof(struct sockaddr_storage));
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, 0, 1);
ac_session_release_reference(session);
}
}
} else if (preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) {
if ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) != 0) {
struct capwap_list_item* itemlist;
struct ac_data_session_handshake* handshake;
/* Search active data dtls handshake */
itemlist = g_ac.datasessionshandshake->first;
while (itemlist != NULL) {
handshake = (struct ac_data_session_handshake*)itemlist->item;
if (!capwap_compare_ip(recvfromaddr, &handshake->wtpaddress) && !capwap_compare_ip(recvtoaddr, &handshake->acaddress)) {
break;
}
/* Next */
itemlist = itemlist->next;
}
/* Create new DTLS handshake */
if (!itemlist) {
itemlist = capwap_itemlist_create(sizeof(struct ac_data_session_handshake));
handshake = (struct ac_data_session_handshake*)itemlist->item;
memset(handshake, 0, sizeof(struct ac_data_session_handshake));
/* */
memcpy(&handshake->socket, socket, sizeof(struct capwap_socket));
memcpy(&handshake->acaddress, recvtoaddr, sizeof(struct sockaddr_storage));
memcpy(&handshake->wtpaddress, recvfromaddr, sizeof(struct sockaddr_storage));
/* Create DTLS session */
if (!capwap_crypt_createsession(&handshake->dtls, CAPWAP_DTLS_DATA_SESSION, &g_ac.dtlscontext, ac_bio_handshake_send, handshake)) {
capwap_itemlist_free(itemlist);
itemlist = NULL;
} else {
if (capwap_crypt_open(&handshake->dtls, recvfromaddr) == CAPWAP_HANDSHAKE_ERROR) {
capwap_crypt_freesession(&handshake->dtls);
capwap_itemlist_free(itemlist);
itemlist = NULL;
} else {
/* Add item to list */
capwap_itemlist_insert_after(g_ac.datasessionshandshake, NULL, itemlist);
}
}
}
/* Decrypt packet */
if (itemlist) {
char temp[CAPWAP_MAX_PACKET_SIZE];
/* */
handshake = (struct ac_data_session_handshake*)itemlist->item;
buffersize = capwap_decrypt_packet(&handshake->dtls, buffer, buffersize, temp, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
session = ac_get_session_from_keepalive(temp, buffersize);
if (!session) {
capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist);
capwap_crypt_close(&handshake->dtls);
capwap_crypt_freesession(&handshake->dtls);
capwap_itemlist_free(itemlist);
} else {
/* Update DTLS session */
capwap_crypt_change_dtls(&handshake->dtls, &session->datadtls);
memcpy(&session->datasocket, &handshake->socket, sizeof(struct capwap_socket));
memcpy(&session->acdataaddress, &handshake->acaddress, sizeof(struct sockaddr_storage));
memcpy(&session->wtpdataaddress, &handshake->wtpaddress, sizeof(struct sockaddr_storage));
capwap_crypt_change_bio_send(&session->datadtls, ac_bio_send, session);
/* Remove temp element */
capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist);
capwap_itemlist_free(itemlist);
/* Add packet*/
ac_session_add_packet(session, temp, buffersize, 0, 1); /* Packet already decrypt */
ac_session_release_reference(session);
}
} else if ((buffersize == CAPWAP_ERROR_SHUTDOWN) || (buffersize == CAPWAP_ERROR_CLOSE)) {
capwap_itemlist_remove(g_ac.datasessionshandshake, itemlist);
capwap_crypt_close(&handshake->dtls);
capwap_crypt_freesession(&handshake->dtls);
capwap_itemlist_free(itemlist);
}
}
}
}
}
/* Create new session */
static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* ctrlsock) {
int result;
struct capwap_list_item* itemlist;
struct ac_session_t* session;
ASSERT(acaddress != NULL);
ASSERT(wtpaddress != NULL);
ASSERT(ctrlsock != NULL);
/* Create new session */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_t));
session = (struct ac_session_t*)itemlist->item;
memset(session, 0, sizeof(struct ac_session_t));
session->count = 2;
memcpy(&session->acctrladdress, acaddress, sizeof(struct sockaddr_storage));
memcpy(&session->wtpctrladdress, wtpaddress, sizeof(struct sockaddr_storage));
memcpy(&session->ctrlsocket, ctrlsock, sizeof(struct capwap_socket));
/* Duplicate state for DFA */
memcpy(&session->dfa, &g_ac.dfa, sizeof(struct ac_state));
session->dfa.acipv4list = capwap_array_clone(g_ac.dfa.acipv4list);
session->dfa.acipv6list = capwap_array_clone(g_ac.dfa.acipv6list);
session->dfa.rfcRetransmitInterval = AC_DEFAULT_RETRANSMIT_INTERVAL;
session->dfa.rfcMaxRetransmit = AC_MAX_RETRANSMIT;
session->dfa.rfcDTLSSessionDelete = AC_DEFAULT_DTLS_SESSION_DELETE;
/* Add default AC list if empty*/
if ((session->dfa.acipv4list->count == 0) && (session->dfa.acipv6list->count == 0)) {
if (session->acctrladdress.ss_family == AF_INET) {
struct capwap_acipv4list_element* acip = (struct capwap_acipv4list_element*)capwap_array_get_item_pointer(session->dfa.acipv4list, 0);
memcpy(&acip->address, &((struct sockaddr_in*)&session->acctrladdress)->sin_addr, sizeof(struct in_addr));
} else if (session->acctrladdress.ss_family == AF_INET6) {
struct capwap_acipv6list_element* acip = (struct capwap_acipv6list_element*)capwap_array_get_item_pointer(session->dfa.acipv6list, 0);
memcpy(&acip->address, &((struct sockaddr_in6*)&session->acctrladdress)->sin6_addr, sizeof(struct in6_addr));
}
}
/* Init */
capwap_event_init(&session->waitpacket);
capwap_lock_init(&session->packetslock);
session->controlpackets = capwap_list_create();
session->datapackets = capwap_list_create();
session->requestfragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
session->responsefragmentpacket = capwap_array_create(sizeof(struct capwap_packet), 0);
session->rxfragmentpacket = capwap_defragment_init_list();
session->mtu = g_ac.mtu;
session->state = CAPWAP_IDLE_STATE;
/* Update session list */
capwap_lock_enter(&g_ac.sessionslock);
capwap_itemlist_insert_after(g_ac.sessions, NULL, itemlist);
capwap_lock_exit(&g_ac.sessionslock);
/* Create thread */
result = pthread_create(&session->threadid, NULL, ac_session_thread, (void*)session);
if (!result) {
pthread_detach(session->threadid);
/* Notify change session list */
capwap_event_signal(&g_ac.changesessionlist);
} else {
capwap_logging_debug("Unable create session thread, error code %d", result);
/* Destroy element */
capwap_lock_enter(&g_ac.sessionslock);
capwap_itemlist_free(capwap_itemlist_remove(g_ac.sessions, itemlist));
capwap_lock_exit(&g_ac.sessionslock);
session = NULL;
}
return session;
}
/* Update statistics */
void ac_update_statistics(void) {
g_ac.descriptor.station = 0; /* TODO */
capwap_lock_enter(&g_ac.sessionslock);
g_ac.descriptor.wtp = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
}
/* Handler signal */
static void ac_signal_handler(int signum) {
if ((signum == SIGINT) || (signum == SIGTERM)) {
g_ac.running = 0;
}
}
/* AC running */
int ac_execute(void) {
int fdscount = CAPWAP_MAX_SOCKETS * 2;
struct pollfd* fds;
int result = CAPWAP_SUCCESSFUL;
int index;
int check;
int isctrlsocket = 0;
struct sockaddr_storage recvfromaddr;
struct sockaddr_storage recvtoaddr;
int isrecvpacket = 0;
struct ac_session_t* session;
struct capwap_socket ctrlsock;
char buffer[CAPWAP_MAX_PACKET_SIZE];
int buffersize;
/* Configure poll struct */
fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fdscount);
if (!fds) {
capwap_outofmemory();
}
/* Retrive all socket for polling */
fdscount = capwap_network_set_pollfd(&g_ac.net, fds, fdscount);
ASSERT(fdscount > 0);
/* Handler signal */
g_ac.running = 1;
signal(SIGINT, ac_signal_handler);
signal(SIGTERM, ac_signal_handler);
/* Start discovery thread */
if (!ac_discovery_start()) {
capwap_free(fds);
capwap_logging_debug("Unable to start discovery thread");
return AC_ERROR_SYSTEM_FAILER;
}
/* */
for (;;) {
/* Receive packet */
isrecvpacket = 0;
buffersize = sizeof(buffer);
index = capwap_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr, NULL);
if (!g_ac.running) {
break;
}
/* */
if (index >= 0) {
/* Detect local address */
if (recvtoaddr.ss_family == AF_UNSPEC) {
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_ac.net.bind_interface, (!(g_ac.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo));
}
}
/* Search the AC session */
isctrlsocket = ((index < (fdscount / 2)) ? 1 : 0);
session = ac_search_session_from_wtpaddress(&recvfromaddr, isctrlsocket);
if (session) {
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0);
/* Release reference */
ac_session_release_reference(session);
} else {
if (isctrlsocket) {
unsigned short sessioncount;
/* Get current session number */
capwap_lock_enter(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
/* PreParsing packet for reduce a DoS attack */
check = capwap_sanity_check(isctrlsocket, CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_header* header = (struct capwap_header*)buffer;
/* Accepted only packet without fragmentation */
if (!IS_FLAG_F_HEADER(header)) {
int headersize = GET_HLEN_HEADER(header) * 4;
if (buffersize >= (headersize + sizeof(struct capwap_control_message))) {
struct capwap_control_message* control = (struct capwap_control_message*)((char*)buffer + headersize);
unsigned long type = ntohl(control->type);
if (type == CAPWAP_DISCOVERY_REQUEST) {
if (sessioncount < g_ac.descriptor.wtplimit) {
ac_discovery_add_packet(buffer, buffersize, fds[index].fd, &recvfromaddr);
}
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
if (sessioncount < g_ac.descriptor.wtplimit) {
/* Retrive socket info */
capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd);
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
if (session) {
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 1);
/* Release reference */
ac_session_release_reference(session);
}
}
}
}
}
} else if (check == CAPWAP_DTLS_PACKET) {
/* Need create a new sessione for check if it is a valid DTLS handshake */
if (sessioncount < g_ac.descriptor.wtplimit) {
/* TODO prevent dos attack add filtering ip for multiple error */
/* Retrive socket info */
capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd);
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
if (session) {
ac_session_add_packet(session, buffer, buffersize, isctrlsocket, 0);
/* Release reference */
ac_session_release_reference(session);
}
}
}
} else {
struct capwap_socket datasocket;
/* Retrieve session by sessionid of data packet */
capwap_get_network_socket(&g_ac.net, &datasocket, fds[index].fd);
ac_update_session_from_datapacket(&datasocket, &recvfromaddr, &recvtoaddr, buffer, buffersize);
}
}
} else if (index == CAPWAP_RECV_ERROR_INTR) {
/* Ignore recv */
continue;
} else if (index == CAPWAP_RECV_ERROR_SOCKET) {
/* Socket close */
break;
}
}
/* Terminate discovery thread */
ac_discovery_stop();
/* Close all sessions */
ac_close_sessions();
/* Wait to terminate all sessions */
for (;;) {
int count;
capwap_lock_enter(&g_ac.sessionslock);
count = g_ac.sessions->count;
capwap_lock_exit(&g_ac.sessionslock);
if (!count) {
break;
}
/* Wait that list is changed */
capwap_logging_debug("Waiting for %d session terminate", count);
capwap_event_wait(&g_ac.changesessionlist);
}
/* Free handshark session */
while (g_ac.datasessionshandshake->first != NULL) {
struct ac_data_session_handshake* handshake = (struct ac_data_session_handshake*)g_ac.datasessionshandshake->first->item;
if (handshake->dtls.enable) {
capwap_crypt_freesession(&handshake->dtls);
}
capwap_itemlist_free(capwap_itemlist_remove(g_ac.datasessionshandshake, g_ac.datasessionshandshake->first));
}
/* Free memory */
capwap_free(fds);
return result;
}

617
src/ac/ac_session.c Normal file
View File

@ -0,0 +1,617 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "ac_session.h"
#define PACKET_TIMEOUT -1
#define DTLS_SHUTDOWN -2
static int ac_network_read(struct ac_session_t* session, void* buffer, int length, int* isctrlpacket, struct timeout_control* timeout) {
long indextimer;
long waittimeout;
ASSERT(session != NULL);
ASSERT(buffer != NULL);
ASSERT(length > 0);
ASSERT(isctrlpacket != NULL);
for (;;) {
if (session->closesession) {
session->closesession = 0;
return DTLS_SHUTDOWN;
}
capwap_lock_enter(&session->packetslock);
if ((session->controlpackets->count > 0) || (session->datapackets->count > 0)) {
int result = 0;
struct capwap_list_item* itempacket;
*isctrlpacket = ((session->controlpackets->count > 0) ? 1 : 0);
/* Get packet */
itempacket = capwap_itemlist_remove_head((*isctrlpacket ? session->controlpackets : session->datapackets));
capwap_lock_exit(&session->packetslock);
if (itempacket) {
struct ac_packet* packet = (struct ac_packet*)itempacket->item;
long packetlength = itempacket->itemsize - sizeof(struct ac_packet);
struct capwap_dtls* dtls = (*isctrlpacket ? &session->ctrldtls : &session->datadtls);
if (!packet->plainbuffer && dtls->enable) {
int oldaction = dtls->action;
/* Decrypt packet */
result = capwap_decrypt_packet(dtls, packet->buffer, packetlength, buffer, length);
if (result == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) {
if (*isctrlpacket) {
if (session->state == CAPWAP_DTLS_CONNECT_STATE) {
ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_set_timeout(session->dfa.rfcWaitJoin, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
}
}
}
} else if (result == CAPWAP_ERROR_SHUTDOWN) {
if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
result = DTLS_SHUTDOWN;
}
}
} else {
if (packetlength <= length) {
memcpy(buffer, packet->buffer, packetlength);
result = packetlength;
}
}
/* Free packet */
capwap_itemlist_free(itempacket);
}
return result;
}
capwap_lock_exit(&session->packetslock);
/* Update timeout */
capwap_update_timeout(timeout);
waittimeout = capwap_get_timeout(timeout, &indextimer);
if ((waittimeout <= 0) && (indextimer != CAPWAP_TIMER_UNDEF)) {
return PACKET_TIMEOUT;
}
/* Wait packet */
capwap_event_wait_timeout(&session->waitpacket, waittimeout);
}
return 0;
}
/* */
static int ac_dfa_execute(struct ac_session_t* session, struct capwap_packet* packet) {
int action = AC_DFA_ACCEPT_PACKET;
ASSERT(session != NULL);
/* Execute state */
switch (session->state) {
case CAPWAP_START_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_START_TO_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_IDLE_TO_DISCOVERY_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_IDLE_TO_DTLS_SETUP_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DISCOVERY_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DISCOVERY_TO_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DISCOVERY_TO_SULKING_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DISCOVERY_TO_DTLS_SETUP_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_SULKING_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_SULKING_TO_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_SETUP_STATE: {
action = ac_dfa_state_dtlssetup(session, packet);
break;
}
case CAPWAP_DTLS_SETUP_TO_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_SETUP_TO_SULKING_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_SETUP_TO_AUTHORIZE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_AUTHORIZE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_AUTHORIZE_TO_DTLS_SETUP_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_AUTHORIZE_TO_DTLS_CONNECT_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_AUTHORIZE_TO_DTLS_TEARDOWN_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_CONNECT_STATE: {
action = ac_dfa_state_dtlsconnect(session, packet);
break;
}
case CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_dtlsconnect_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_DTLS_CONNECT_TO_JOIN_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_teardown(session, packet);
break;
}
case CAPWAP_DTLS_TEARDOWN_TO_IDLE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_TEARDOWN_TO_SULKING_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_DTLS_TEARDOWN_TO_DEAD_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_JOIN_STATE: {
action = ac_dfa_state_join(session, packet);
break;
}
case CAPWAP_POSTJOIN_STATE: {
action = ac_dfa_state_postjoin(session, packet);
break;
}
case CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_join_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_JOIN_TO_IMAGE_DATA_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_JOIN_TO_CONFIGURE_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_IMAGE_DATA_STATE: {
action = ac_dfa_state_imagedata(session, packet);
break;
}
case CAPWAP_IMAGE_DATA_TO_RESET_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_IMAGE_DATA_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_imagedata_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_CONFIGURE_STATE: {
action = ac_dfa_state_configure(session, packet);
break;
}
case CAPWAP_CONFIGURE_TO_RESET_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_configure_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_CONFIGURE_TO_DATA_CHECK_STATE: {
/* Never called with this state */
ASSERT(0);
break;
}
case CAPWAP_RESET_STATE: {
action = ac_dfa_state_reset(session, packet);
break;
}
case CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_reset_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_DATA_CHECK_STATE: {
action = ac_dfa_state_datacheck(session, packet);
break;
}
case CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_datacheck_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_DATA_CHECK_TO_RUN_STATE: {
action = ac_dfa_state_datacheck_to_run(session, packet);
break;
}
case CAPWAP_RUN_STATE: {
action = ac_dfa_state_run(session, packet);
break;
}
case CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE: {
action = ac_dfa_state_run_to_dtlsteardown(session, packet);
break;
}
case CAPWAP_RUN_TO_RESET_STATE: {
action = ac_dfa_state_run_to_reset(session, packet);
break;
}
case CAPWAP_DEAD_STATE: {
action = ac_dfa_state_dead(session, packet);
break;
}
default: {
capwap_logging_debug("Unknown action event: %lu", session->state);
break;
}
}
return action;
}
static void ac_session_run(struct ac_session_t* session) {
int check;
int length;
int isctrlsocket;
int action = AC_DFA_ACCEPT_PACKET;
char buffer[CAPWAP_MAX_PACKET_SIZE];
ASSERT(session != NULL);
/* Configure DFA */
if (g_ac.enabledtls) {
action = AC_DFA_NO_PACKET;
ac_dfa_change_state(session, CAPWAP_DTLS_SETUP_STATE);
capwap_set_timeout(session->dfa.rfcWaitDTLS, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
} else {
/* Wait Join request */
ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_set_timeout(session->dfa.rfcWaitJoin, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
}
while (action != AC_DFA_DEAD) {
/* Get packet */
if ((action == AC_DFA_ACCEPT_PACKET) || (action == AC_DFA_DROP_PACKET)) {
length = ac_network_read(session, buffer, sizeof(buffer), &isctrlsocket, &session->timeout);
if (length < 0) {
if (length == PACKET_TIMEOUT) {
action = ac_dfa_execute(session, NULL); /* Timeout */
} else if (length == DTLS_SHUTDOWN) {
action = ac_session_teardown_connection(session);
}
} else if (length > 0) {
/* Accept data packet only in running state */
if (isctrlsocket || (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) || (session->state == CAPWAP_RUN_STATE)) {
/* Check generic capwap packet */
check = capwap_sanity_check(isctrlsocket, CAPWAP_UNDEF_STATE, buffer, length, 0, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_packet packet;
check = capwap_defragment_packets(&session->wtpctrladdress, buffer, length, session->rxfragmentpacket, &packet);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
int ignorepacket = 0;
if (isctrlsocket) {
/* Check for already response to packet */
if (capwap_recv_retrasmitted_request(&session->ctrldtls, &packet, session->remoteseqnumber, session->lastrecvpackethash, &session->ctrlsocket, session->responsefragmentpacket, &session->acctrladdress, &session->wtpctrladdress)) {
ignorepacket = 1;
}
/* Check message type */
if (!capwap_check_message_type(&session->ctrldtls, &packet, session->mtu)) {
ignorepacket = 1;
}
}
/* */
if (!ignorepacket && (action == AC_DFA_ACCEPT_PACKET)) {
memcpy(&packet.socket, (isctrlsocket ? &session->ctrlsocket : &session->datasocket), sizeof(struct capwap_socket));
action = ac_dfa_execute(session, &packet);
}
/* Free packet */
capwap_free_packet(&packet);
} else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) {
/* Discard fragments */
capwap_defragment_remove_sender(session->rxfragmentpacket, &session->wtpctrladdress);
}
}
}
}
} else {
action = ac_dfa_execute(session, NULL);
}
}
/* Release reference session */
if (!ac_session_release_reference(session)) {
capwap_logging_debug("Reference session is > 0 to exit thread");
}
}
/* Change WTP state machine */
void ac_dfa_change_state(struct ac_session_t* session, int state) {
ASSERT(session != NULL);
if (state != session->state) {
#ifdef DEBUG
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Session AC %s change state from %s to %s", sessionname, capwap_dfa_getname(session->state), capwap_dfa_getname(state));
#endif
session->state = state;
}
}
/* Teardown connection */
int ac_session_teardown_connection(struct ac_session_t* session) {
ASSERT(session != NULL);
/* Close DTSL Control */
if (session->ctrldtls.enable) {
capwap_crypt_close(&session->ctrldtls);
}
/* Close DTLS Data */
if (session->datadtls.enable) {
capwap_crypt_close(&session->datadtls);
}
/* */
capwap_killall_timeout(&session->timeout);
capwap_set_timeout(session->dfa.rfcDTLSSessionDelete, &session->timeout, CAPWAP_TIMER_CONTROL_CONNECTION);
ac_dfa_change_state(session, CAPWAP_DTLS_TEARDOWN_STATE);
return AC_DFA_DROP_PACKET;
}
/* Release reference of session */
int ac_session_release_reference(struct ac_session_t* session) {
int remove = 0;
struct capwap_list_item* search;
ASSERT(session != NULL);
capwap_lock_enter(&g_ac.sessionslock);
session->count--;
if (!session->count) {
search = g_ac.sessions->first;
while (search != NULL) {
struct ac_session_t* item = (struct ac_session_t*)search->item;
if (session == item) {
/* Free DTSL Control */
capwap_crypt_freesession(&session->ctrldtls);
/* Free DTLS Data */
capwap_crypt_freesession(&session->datadtls);
/* Free resource */
capwap_event_destroy(&session->waitpacket);
capwap_lock_exit(&session->packetslock);
capwap_list_free(session->controlpackets);
capwap_list_free(session->datapackets);
capwap_defragment_free_list(session->rxfragmentpacket);
/* Free fragments packet */
capwap_fragment_free(session->requestfragmentpacket);
capwap_fragment_free(session->responsefragmentpacket);
capwap_array_free(session->requestfragmentpacket);
capwap_array_free(session->responsefragmentpacket);
/* Free DFA resource */
capwap_array_free(session->dfa.acipv4list);
capwap_array_free(session->dfa.acipv6list);
/* Remove item from list */
remove = 1;
capwap_itemlist_free(capwap_itemlist_remove(g_ac.sessions, search));
capwap_event_signal(&g_ac.changesessionlist);
break;
}
search = search->next;
}
}
capwap_lock_exit(&g_ac.sessionslock);
return remove;
}
/* */
void* ac_session_thread(void* param) {
ASSERT(param != NULL);
capwap_logging_debug("Session start");
ac_session_run((struct ac_session_t*)param);
capwap_logging_debug("Session end");
/* Thread exit */
pthread_exit(NULL);
return NULL;
}
/* */
void ac_get_control_information(struct capwap_list* controllist) {
struct capwap_list* addrlist;
struct capwap_list_item* item;
ASSERT(controllist != NULL);
/* Detect local address */
addrlist = capwap_list_create();
capwap_interface_list(&g_ac.net, addrlist);
/* Prepare control list */
for (item = addrlist->first; item != NULL; item = item->next) {
struct capwap_list_item* itemcontrol;
struct ac_session_control* sessioncontrol;
struct sockaddr_storage* address = (struct sockaddr_storage*)item->item;
/* */
itemcontrol = capwap_itemlist_create(sizeof(struct ac_session_control));
sessioncontrol = (struct ac_session_control*)itemcontrol->item;
memcpy(&sessioncontrol->localaddress, address, sizeof(struct sockaddr_storage));
sessioncontrol->count = 0;
/* Add */
capwap_itemlist_insert_after(controllist, NULL, itemcontrol);
}
/* Free local address list */
capwap_list_free(addrlist);
/* */
capwap_lock_enter(&g_ac.sessionslock);
/* Get wtp count from any local address */
for (item = controllist->first; item != NULL; item = item->next) {
struct capwap_list_item* search;
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
for (search = g_ac.sessions->first; search != NULL; search = search->next) {
struct ac_session_t* session = (struct ac_session_t*)search->item;
if (!capwap_compare_ip(&session->acctrladdress, &sessioncontrol->localaddress)) {
sessioncontrol->count++;
}
}
}
/* */
capwap_lock_exit(&g_ac.sessionslock);
}
/* */
void ac_free_reference_last_request(struct ac_session_t* session) {
ASSERT(session);
capwap_fragment_free(session->requestfragmentpacket);
}
/* */
void ac_free_reference_last_response(struct ac_session_t* session) {
ASSERT(session);
capwap_fragment_free(session->responsefragmentpacket);
memset(&session->lastrecvpackethash[0], 0, sizeof(session->lastrecvpackethash));
}

112
src/ac/ac_session.h Normal file
View File

@ -0,0 +1,112 @@
#ifndef __AC_SESSION_HEADER__
#define __AC_SESSION_HEADER__
#include "capwap_dtls.h"
#define AC_DFA_NO_PACKET 0
#define AC_DFA_ACCEPT_PACKET 1
#define AC_DFA_DROP_PACKET 2
#define AC_DFA_DEAD 3
/* AC packet */
struct ac_packet {
int plainbuffer;
char buffer[0];
};
/* */
struct ac_session_control {
struct sockaddr_storage localaddress;
unsigned short count;
};
/* AC sessions */
struct ac_session_t {
struct ac_state dfa;
unsigned long count;
struct sockaddr_storage acctrladdress;
struct sockaddr_storage acdataaddress;
struct sockaddr_storage wtpctrladdress;
struct sockaddr_storage wtpdataaddress;
struct capwap_socket ctrlsocket;
struct capwap_socket datasocket;
struct timeout_control timeout;
struct capwap_sessionid_element sessionid;
unsigned short binding;
struct capwap_dtls ctrldtls;
struct capwap_dtls datadtls;
int closesession;
pthread_t threadid;
capwap_event_t waitpacket;
capwap_lock_t packetslock;
struct capwap_list* controlpackets;
struct capwap_list* datapackets;
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short mtu;
unsigned short fragmentid;
capwap_fragment_list* rxfragmentpacket;
capwap_fragment_packet_array* requestfragmentpacket;
capwap_fragment_packet_array* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
unsigned long state;
struct capwap_imageidentifier_element startupimage;
};
void* ac_session_thread(void* param);
int ac_session_teardown_connection(struct ac_session_t* session);
int ac_session_release_reference(struct ac_session_t* session);
void ac_dfa_change_state(struct ac_session_t* session, int state);
void ac_get_control_information(struct capwap_list* controllist);
void ac_free_reference_last_request(struct ac_session_t* session);
void ac_free_reference_last_response(struct ac_session_t* session);
/* */
int ac_dfa_state_join(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_join_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param);
int ac_dfa_state_dtlssetup(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_dtlsconnect(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_dtlsconnect_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_configure(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_configure_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_datacheck_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_imagedata(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_imagedata_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_run(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_run_to_reset(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_run_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_reset(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_reset_to_dtlsteardown(struct ac_session_t* session, struct capwap_packet* packet);
/* */
int ac_dfa_state_teardown(struct ac_session_t* session, struct capwap_packet* packet);
int ac_dfa_state_dead(struct ac_session_t* session, struct capwap_packet* packet);
#endif /* __AC_SESSION_HEADER__ */

151
src/common/capwap.c Normal file
View File

@ -0,0 +1,151 @@
#include "capwap.h"
/* Helper exit */
void capwap_exit(int errorcode) {
exit(errorcode);
}
/* Helper timeout calc */
void capwap_init_timeout(struct timeout_control* timeout) {
ASSERT(timeout);
memset(timeout, 0, sizeof(struct timeout_control));
}
void capwap_update_timeout(struct timeout_control* timeout) {
int i;
struct timeval now;
ASSERT(timeout);
gettimeofday(&now, NULL);
for (i = 0; i < CAPWAP_MAX_TIMER; i++) {
if (timeout->items[i].enable && (timeout->items[i].delta >= 0)) {
timeout->items[i].delta = (timeout->items[i].timestop.tv_sec - now.tv_sec) * 1000 + (timeout->items[i].timestop.tv_usec - now.tv_usec) / 1000;
if (timeout->items[i].delta < 0) {
timeout->items[i].delta = 0;
} else if (timeout->items[i].delta > timeout->items[i].durate) {
/* Changed system time */
timeout->items[i].delta = timeout->items[i].durate;
memcpy(&timeout->items[i].timestop, &now, sizeof(struct timeval));
timeout->items[i].timestop.tv_sec += timeout->items[i].durate;
}
}
}
}
long capwap_get_timeout(struct timeout_control* timeout, long* index) {
long i;
long delta = 0;
ASSERT(timeout != NULL);
ASSERT(index != NULL);
*index = CAPWAP_TIMER_UNDEF;
for (i = 0; i < CAPWAP_MAX_TIMER; i++) {
if (timeout->items[i].enable) {
if (timeout->items[i].delta <= 0) {
*index = i;
delta = 0;
break;
} else if (!delta || (delta > timeout->items[i].delta)) {
*index = i;
delta = timeout->items[i].delta;
}
}
}
return delta;
}
int capwap_is_enable_timeout(struct timeout_control* timeout, unsigned long index) {
ASSERT(timeout != NULL);
ASSERT(index < CAPWAP_MAX_TIMER);
return (timeout->items[index].enable ? 1 : 0);
}
int capwap_is_timeout(struct timeout_control* timeout, unsigned long index) {
ASSERT(timeout != NULL);
ASSERT(index < CAPWAP_MAX_TIMER);
if (timeout->items[index].enable && (timeout->items[index].delta <= 0)) {
return 1;
}
return 0;
}
void capwap_set_timeout(unsigned long value, struct timeout_control* timeout, unsigned long index) {
ASSERT(timeout != NULL);
ASSERT(index < CAPWAP_MAX_TIMER);
/* Set timeout in ms */
timeout->items[index].enable = 1;
timeout->items[index].delta = value * 1000;
timeout->items[index].durate = value * 1000;
gettimeofday(&timeout->items[index].timestop, NULL);
timeout->items[index].timestop.tv_sec += value;
}
void capwap_kill_timeout(struct timeout_control* timeout, unsigned long index) {
ASSERT(timeout != NULL);
ASSERT(index < CAPWAP_MAX_TIMER);
timeout->items[index].enable = 0;
}
void capwap_killall_timeout(struct timeout_control* timeout) {
long i;
ASSERT(timeout != NULL);
for (i = 0; i < CAPWAP_MAX_TIMER; i++) {
timeout->items[i].enable = 0;
}
}
/* Init randon generator */
void capwap_init_rand(void) {
srand(time(NULL));
}
/* Get random number */
int capwap_get_rand(int max) {
if ((max < 0) || (max > RAND_MAX)) {
max = RAND_MAX;
}
return (rand() % max);
}
/* Duplicate string */
char* capwap_duplicate_string(const char* source) {
char* clone;
ASSERT(source != NULL);
clone = capwap_alloc(sizeof(char) * (strlen(source) + 1));
if (!clone) {
capwap_outofmemory();
}
strcpy(clone, source);
return clone;
}
/* Buffer clone */
void* capwap_clone(void* buffer, int buffersize) {
void* bufferclone;
ASSERT(buffer != NULL);
ASSERT(buffersize > 0);
bufferclone = capwap_alloc(buffersize);
if (!bufferclone) {
capwap_outofmemory();
}
return memcpy(bufferclone, buffer, buffersize);
}

101
src/common/capwap.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef __CAPWAP_HEADER__
#define __CAPWAP_HEADER__
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <net/if.h>
//TODO:
//#ifdef NATIVE_UDPLITE_HEADER
//#include <netinet/udplite.h>
//#else
//#define IPPROTO_UDPLITE 136
#define SOL_UDPLITE 136
#define UDPLITE_SEND_CSCOV 10
//#endif
/* Endian */
#ifdef WIN32
#define CAPWAP_LITTLE_ENDIAN
#else
#if __BYTE_ORDER == __BIG_ENDIAN
#define CAPWAP_BIG_ENDIAN
#else
#define CAPWAP_LITTLE_ENDIAN
#endif
#endif
/* Min & Max */
#ifndef max
#define max(a,b) ((a) >= (b) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) ((a) <= (b) ? (a) : (b))
#endif
/* config */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* standard include */
#include "capwap_logging.h"
#include "capwap_debug.h"
#include "capwap_error.h"
/* Helper exit */
void capwap_exit(int errorcode);
/* Random generator */
void capwap_init_rand(void);
int capwap_get_rand(int max);
/* Helper timeout calc */
struct timeout_control_item {
int enable;
long delta;
unsigned long durate;
struct timeval timestop;
};
#define CAPWAP_TIMER_UNDEF -1
#define CAPWAP_TIMER_CONTROL_CONNECTION 0
#define CAPWAP_TIMER_CONTROL_ECHO 1
#define CAPWAP_TIMER_DATA_KEEPALIVE 2
#define CAPWAP_TIMER_DATA_KEEPALIVEDEAD 3
#define CAPWAP_MAX_TIMER 4
struct timeout_control {
struct timeout_control_item items[CAPWAP_MAX_TIMER];
};
void capwap_init_timeout(struct timeout_control* timeout);
long capwap_get_timeout(struct timeout_control* timeout, long* index);
void capwap_update_timeout(struct timeout_control* timeout);
void capwap_set_timeout(unsigned long value, struct timeout_control* timeout, unsigned long index);
void capwap_kill_timeout(struct timeout_control* timeout, unsigned long index);
void capwap_killall_timeout(struct timeout_control* timeout);
int capwap_is_enable_timeout(struct timeout_control* timeout, unsigned long index);
int capwap_is_timeout(struct timeout_control* timeout, unsigned long index);
/* */
#define capwap_outofmemory() capwap_logging_fatal("Out of memory %s(%d)", __FILE__, __LINE__); \
capwap_exit(CAPWAP_OUT_OF_MEMORY);
/* Helper buffer copy */
char* capwap_duplicate_string(const char* source);
void* capwap_clone(void* buffer, int buffersize);
#endif /* __CAPWAP_HEADER__ */

92
src/common/capwap_array.c Normal file
View File

@ -0,0 +1,92 @@
#include "capwap.h"
#include "capwap_array.h"
/* */
struct capwap_array* capwap_array_create(unsigned short itemsize, unsigned long initcount) {
struct capwap_array* array;
ASSERT(itemsize > 0);
array = (struct capwap_array*)capwap_alloc(sizeof(struct capwap_array));
if (!array) {
capwap_outofmemory();
}
memset(array, 0, sizeof(struct capwap_array));
array->itemsize = itemsize;
if (initcount > 0) {
capwap_array_resize(array, initcount);
}
return array;
}
/* */
struct capwap_array* capwap_array_clone(struct capwap_array* array) {
unsigned long i;
struct capwap_array* clone;
ASSERT (array != NULL);
/* Clone array e items */
clone = capwap_array_create(array->itemsize, array->count);
for (i = 0; i < array->count; i++) {
memcpy(capwap_array_get_item_pointer(clone, i), capwap_array_get_item_pointer(array, i), array->itemsize);
}
return clone;
}
/* */
void capwap_array_free(struct capwap_array* array) {
ASSERT(array != NULL);
if (array->buffer) {
capwap_free(array->buffer);
}
capwap_free(array);
}
/* */
void* capwap_array_get_item_pointer(struct capwap_array* array, unsigned long pos) {
ASSERT(array != NULL);
ASSERT((array->count == 0) || (array->buffer != NULL));
if (pos >= array->count) {
capwap_array_resize(array, pos + 1);
}
return (void*)(((char*)array->buffer) + array->itemsize * pos);
}
/* */
void capwap_array_resize(struct capwap_array* array, unsigned long count) {
void* newbuffer = NULL;
ASSERT(array != NULL);
ASSERT(array->itemsize > 0);
if (array->count == count) {
return;
}
if (count > 0) {
newbuffer = capwap_alloc(array->itemsize * count);
if (!newbuffer) {
capwap_outofmemory();
}
}
if (array->buffer) {
if (newbuffer != NULL) {
memcpy(newbuffer, array->buffer, array->itemsize * min(array->count, count));
}
capwap_free(array->buffer);
}
array->buffer = newbuffer;
array->count = count;
}

21
src/common/capwap_array.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __CAPWAP_ARRAY_HEADER__
#define __CAPWAP_ARRAY_HEADER__
struct capwap_array {
void* buffer;
unsigned short itemsize;
unsigned long count;
};
struct capwap_array* capwap_array_create(unsigned short itemsize, unsigned long initcount);
struct capwap_array* capwap_array_clone(struct capwap_array* array);
void capwap_array_free(struct capwap_array* array);
void* capwap_array_get_item_pointer(struct capwap_array* array, unsigned long pos);
void capwap_array_resize(struct capwap_array* array, unsigned long count);
/* Helper */
#define capwap_array_getitem(x, y, z) *((z*)capwap_array_get_item_pointer((x), (y)))
#define capwap_array_setnewitem(x, y, z) *((z*)capwap_array_get_item_pointer((x), (x)->count)) = (y)
#endif /* __CAPWAP_ARRAY_HEADER__ */

161
src/common/capwap_debug.c Normal file
View File

@ -0,0 +1,161 @@
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "capwap_logging.h"
#define CANARY 0xaaaaaaaa
#define BACKTRACE_BUFFER 256
#ifndef DEBUG_BREAKPOINT
#define DEBUG_BREAKPOINT() __asm__("int3")
#endif
/* Memory block */
struct capwap_memory_block {
void* item;
size_t size;
const char* file;
int line;
void* backtrace[BACKTRACE_BUFFER];
int backtrace_count;
struct capwap_memory_block* next;
};
static struct capwap_memory_block* g_memoryblocks = NULL;
/* Alloc memory block */
void* capwap_alloc_debug(size_t size, const char* file, const int line) {
struct capwap_memory_block* block;
/* Request size > 0 */
if (size <= 0) {
capwap_logging_debug("%s(%d): Invalid memory size %d", file, line, size);
DEBUG_BREAKPOINT();
return NULL;
}
/* Alloc block with memory block and canary */
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size + 4);
if (!block) {
capwap_logging_debug("Out of memory %s(%d)", __FILE__, __LINE__);
DEBUG_BREAKPOINT();
return NULL;
}
/* Info memory block */
block->item = (void*)(((char*)block) + sizeof(struct capwap_memory_block));
block->size = size;
block->file = file;
block->line = line;
block->backtrace_count = backtrace(block->backtrace, BACKTRACE_BUFFER);
block->next = g_memoryblocks;
/* Canary */
*((unsigned long*)(((char*)block->item) + block->size)) = CANARY;
g_memoryblocks = block;
return block->item;
}
/* Free memory block */
void capwap_free_debug(void* p, const char* file, const int line) {
struct capwap_memory_block* block;
struct capwap_memory_block* findblock;
struct capwap_memory_block* prevblock;
if (!p) {
capwap_logging_debug("%s(%d): Free NULL pointer", file, line);
DEBUG_BREAKPOINT();
return;
}
/* Memory block */
if ((size_t)p <= sizeof(struct capwap_memory_block)) {
capwap_logging_debug("%s(%d): Invalid pointer", file, line);
DEBUG_BREAKPOINT();
return;
}
block = (struct capwap_memory_block*)((char*)p - sizeof(struct capwap_memory_block));
if (block->item != p) {
capwap_logging_debug("%s(%d): Invalid pointer", file, line);
DEBUG_BREAKPOINT();
return;
}
/* Check canary */
if (*((unsigned long*)(((char*)block->item) + block->size)) != CANARY) {
capwap_logging_debug("%s(%d): Invalid canary allocted in %s(%d)", file, line, block->file, block->line);
DEBUG_BREAKPOINT();
return;
}
/* Find memory block */
prevblock = NULL;
findblock = g_memoryblocks;
while (findblock != NULL) {
if (findblock == block) {
if (!prevblock) {
g_memoryblocks = block->next;
} else {
prevblock->next = block->next;
}
/* Invalidate block */
memset(block, 0, sizeof(struct capwap_memory_block));
free(block);
return;
}
/* Next */
prevblock = findblock;
findblock = findblock->next;
}
capwap_logging_debug("%s(%d): Unable to find memory block", file, line);
}
/* Dump memory alloced */
void capwap_dump_memory(void) {
char** backtrace_functions;
struct capwap_memory_block* findblock;
findblock = g_memoryblocks;
while (findblock != NULL) {
capwap_logging_debug("%s(%d): block at %p, %d bytes long", findblock->file, findblock->line, findblock->item, findblock->size);
backtrace_functions = backtrace_symbols(findblock->backtrace, findblock->backtrace_count);
if (backtrace_functions) {
int j;
/* Skipping capwap_alloc_debug function print out */
for (j = 1; j < findblock->backtrace_count; j++) {
capwap_logging_debug("\t%s", backtrace_functions[j]);
}
free(backtrace_functions);
}
/* Next */
findblock = findblock->next;
}
}
/* Check if all memory is free */
int capwap_check_memory_leak(int verbose) {
if ((g_memoryblocks != NULL) && (verbose != 0)) {
capwap_logging_debug("*** Detected memory leaks ! ***");
capwap_dump_memory();
capwap_logging_debug("*******************************");
}
return ((g_memoryblocks != NULL) ? 1 : 0);
}

37
src/common/capwap_debug.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __CAPWAP_DEBUG_HEADER__
#define __CAPWAP_DEBUG_HEADER__
#ifdef DEBUG
#define DEBUG_BREAKPOINT() __asm__("int3")
#define ASSERT(expr) if (!(expr)) { \
capwap_logging_fatal("Assertion failed \'%s\': %s(%d)", #expr, __FILE__, __LINE__); \
DEBUG_BREAKPOINT(); \
}
/* Custom memory management */
#define capwap_alloc(x) capwap_alloc_debug(x, __FILE__, __LINE__)
void* capwap_alloc_debug(size_t size, const char* file, const int line);
#define capwap_free(x) capwap_free_debug(x, __FILE__, __LINE__)
void capwap_free_debug(void* p, const char* file, const int line);
int capwap_check_memory_leak(int verbose);
void capwap_dump_memory(void);
#else
#define DEBUG_BREAKPOINT()
#define ASSERT(expr)
/* Standard memory management */
#define capwap_alloc(x) (void*)malloc(x)
#define capwap_free(x) free(x)
#define capwap_check_memory_leak(x) (0)
#define capwap_dump_memory() (0)
#endif
#endif /* __CAPWAP_DEBUG_HEADER__ */

61
src/common/capwap_dfa.c Normal file
View File

@ -0,0 +1,61 @@
#include "capwap.h"
#include "capwap_dfa.h"
static char* l_nameofstate[] = {
"START", /* CAPWAP_START_STATE */
"START_TO_IDLE", /* CAPWAP_START_TO_IDLE_STATE */
"IDLE", /* CAPWAP_IDLE_STATE */
"IDLE_TO_DISCOVERY", /* CAPWAP_IDLE_TO_DISCOVERY_STATE */
"IDLE_TO_DTLS_SETUP", /* CAPWAP_IDLE_TO_DTLS_SETUP_STATE */
"DISCOVERY", /* CAPWAP_DISCOVERY_STATE */
"DISCOVERY_TO_IDLE", /* CAPWAP_DISCOVERY_TO_IDLE_STATE */
"DISCOVERY_TO_SULKING", /* CAPWAP_DISCOVERY_TO_SULKING_STATE */
"DISCOVERY_TO_DTLS_SETUP", /* CAPWAP_DISCOVERY_TO_DTLS_SETUP_STATE */
"SULKING", /* CAPWAP_SULKING_STATE */
"SULKING_TO_IDLE", /* CAPWAP_SULKING_TO_IDLE_STATE */
"DTLS_SETUP", /* CAPWAP_DTLS_SETUP_STATE */
"DTLS_SETUP_TO_IDLE", /* CAPWAP_DTLS_SETUP_TO_IDLE_STATE */
"DTLS_SETUP_TO_SULKING", /* CAPWAP_DTLS_SETUP_TO_SULKING_STATE */
"DTLS_SETUP_TO_AUTHORIZE", /* CAPWAP_DTLS_SETUP_TO_AUTHORIZE_STATE */
"AUTHORIZE", /* CAPWAP_AUTHORIZE_STATE */
"AUTHORIZE_TO_DTLS_SETUP", /* CAPWAP_AUTHORIZE_TO_DTLS_SETUP_STATE */
"AUTHORIZE_TO_DTLS_CONNECT", /* CAPWAP_AUTHORIZE_TO_DTLS_CONNECT_STATE */
"AUTHORIZE_TO_DTLS_TEARDOWN", /* CAPWAP_AUTHORIZE_TO_DTLS_TEARDOWN_STATE */
"DTLS_CONNECT", /* CAPWAP_DTLS_CONNECT_STATE */
"DTLS_CONNECT_TO_DTLS_TEARDOWN", /* CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE */
"DTLS_CONNECT_TO_JOIN", /* CAPWAP_DTLS_CONNECT_TO_JOIN_STATE */
"DTLS_TEARDOWN", /* CAPWAP_DTLS_TEARDOWN_STATE */
"DTLS_TEARDOWN_TO_IDLE", /* CAPWAP_DTLS_TEARDOWN_TO_IDLE_STATE */
"DTLS_TEARDOWN_TO_SULKING", /* CAPWAP_DTLS_TEARDOWN_TO_SULKING_STATE */
"DTLS_TEARDOWN_TO_DEAD", /* CAPWAP_DTLS_TEARDOWN_TO_DEAD_STATE */
"JOIN", /* CAPWAP_JOIN_STATE */
"POST_JOIN", /* CAPWAP_POSTJOIN_STATE */
"JOIN_TO_DTLS_TEARDOWN", /* CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE */
"JOIN_TO_IMAGE_DATA", /* CAPWAP_JOIN_TO_IMAGE_DATA_STATE */
"JOIN_TO_CONFIGURE", /* CAPWAP_JOIN_TO_CONFIGURE_STATE */
"IMAGE_DATA", /* CAPWAP_IMAGE_DATA_STATE */
"IMAGE_DATA_TO_RESET", /* CAPWAP_IMAGE_DATA_TO_RESET_STATE */
"IMAGE_DATA_TO_DTLS_TEARDOWN", /* CAPWAP_IMAGE_DATA_TO_DTLS_TEARDOWN_STATE */
"CONFIGURE", /* CAPWAP_CONFIGURE_STATE */
"CONFIGURE_TO_RESET", /* CAPWAP_CONFIGURE_TO_RESET_STATE */
"CONFIGURE_TO_DTLS_TEARDOWN", /* CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE */
"CONFIGURE_TO_DATA_CHECK", /* CAPWAP_CONFIGURE_TO_DATA_CHECK_STATE */
"RESET", /* CAPWAP_RESET_STATE */
"RESET_TO_DTLS_TEARDOWN", /* CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE */
"DATA_CHECK", /* CAPWAP_DATA_CHECK_STATE */
"DATA_CHECK_TO_DTLS_TEARDOWN", /* CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE */
"DATA_CHECK_TO_RUN", /* CAPWAP_DATA_CHECK_TO_RUN_STATE */
"RUN", /* CAPWAP_RUN_STATE */
"RUN_TO_DTLS_TEARDOWN", /* CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE */
"RUN_TO_RESET", /* CAPWAP_RUN_TO_RESET_STATE */
"DEAD" /* CAPWAP_DEAD_STATE */
};
/* */
char* capwap_dfa_getname(int state) {
if ((state < 0) || (state > CAPWAP_LAST_STATE)) {
return "";
}
return l_nameofstate[state];
}

57
src/common/capwap_dfa.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef __CAPWAP_DFA_HEADER__
#define __CAPWAP_DFA_HEADER__
#define CAPWAP_UNDEF_STATE -1
#define CAPWAP_START_STATE 0
#define CAPWAP_START_TO_IDLE_STATE 1
#define CAPWAP_IDLE_STATE 2
#define CAPWAP_IDLE_TO_DISCOVERY_STATE 3
#define CAPWAP_IDLE_TO_DTLS_SETUP_STATE 4
#define CAPWAP_DISCOVERY_STATE 5
#define CAPWAP_DISCOVERY_TO_IDLE_STATE 6
#define CAPWAP_DISCOVERY_TO_SULKING_STATE 7
#define CAPWAP_DISCOVERY_TO_DTLS_SETUP_STATE 8
#define CAPWAP_SULKING_STATE 9
#define CAPWAP_SULKING_TO_IDLE_STATE 10
#define CAPWAP_DTLS_SETUP_STATE 11
#define CAPWAP_DTLS_SETUP_TO_IDLE_STATE 12
#define CAPWAP_DTLS_SETUP_TO_SULKING_STATE 13
#define CAPWAP_DTLS_SETUP_TO_AUTHORIZE_STATE 14
#define CAPWAP_AUTHORIZE_STATE 15
#define CAPWAP_AUTHORIZE_TO_DTLS_SETUP_STATE 16
#define CAPWAP_AUTHORIZE_TO_DTLS_CONNECT_STATE 17
#define CAPWAP_AUTHORIZE_TO_DTLS_TEARDOWN_STATE 18
#define CAPWAP_DTLS_CONNECT_STATE 19
#define CAPWAP_DTLS_CONNECT_TO_DTLS_TEARDOWN_STATE 20
#define CAPWAP_DTLS_CONNECT_TO_JOIN_STATE 21
#define CAPWAP_DTLS_TEARDOWN_STATE 22
#define CAPWAP_DTLS_TEARDOWN_TO_IDLE_STATE 23
#define CAPWAP_DTLS_TEARDOWN_TO_SULKING_STATE 24
#define CAPWAP_DTLS_TEARDOWN_TO_DEAD_STATE 25
#define CAPWAP_JOIN_STATE 26
#define CAPWAP_POSTJOIN_STATE 27
#define CAPWAP_JOIN_TO_DTLS_TEARDOWN_STATE 28
#define CAPWAP_JOIN_TO_IMAGE_DATA_STATE 29
#define CAPWAP_JOIN_TO_CONFIGURE_STATE 30
#define CAPWAP_IMAGE_DATA_STATE 31
#define CAPWAP_IMAGE_DATA_TO_RESET_STATE 32
#define CAPWAP_IMAGE_DATA_TO_DTLS_TEARDOWN_STATE 33
#define CAPWAP_CONFIGURE_STATE 34
#define CAPWAP_CONFIGURE_TO_RESET_STATE 35
#define CAPWAP_CONFIGURE_TO_DTLS_TEARDOWN_STATE 36
#define CAPWAP_CONFIGURE_TO_DATA_CHECK_STATE 37
#define CAPWAP_RESET_STATE 38
#define CAPWAP_RESET_TO_DTLS_TEARDOWN_STATE 39
#define CAPWAP_DATA_CHECK_STATE 40
#define CAPWAP_DATA_CHECK_TO_DTLS_TEARDOWN_STATE 41
#define CAPWAP_DATA_CHECK_TO_RUN_STATE 42
#define CAPWAP_RUN_STATE 43
#define CAPWAP_RUN_TO_DTLS_TEARDOWN_STATE 44
#define CAPWAP_RUN_TO_RESET_STATE 45
#define CAPWAP_DEAD_STATE 46
#define CAPWAP_LAST_STATE 46
/* */
char* capwap_dfa_getname(int state);
#endif /* __CAPWAP_DFA_HEADER__ */

785
src/common/capwap_dtls.c Normal file
View File

@ -0,0 +1,785 @@
#include "capwap.h"
#include "capwap_dtls.h"
#include "capwap_protocol.h"
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/conf.h>
#define CAPWAP_DTLS_CERT_VERIFY_DEPTH 1
#define CAPWAP_DTLS_MTU_SIZE 16384
/* */
static int capwap_bio_method_new(BIO* bio);
static int capwap_bio_method_free(BIO* bio);
static int capwap_bio_method_puts(BIO* bio, const char* str);
static int capwap_bio_method_read(BIO* bio, char* str, int length);
static int capwap_bio_method_write(BIO* bio, const char* str, int length);
static long capwap_bio_method_ctrl(BIO* bio, int cmd, long num, void* ptr);
/* OpenSSL BIO methods */
static BIO_METHOD bio_methods_memory = {
BIO_TYPE_DGRAM,
"dtls capwap packet",
capwap_bio_method_write,
capwap_bio_method_read,
capwap_bio_method_puts,
NULL,
capwap_bio_method_ctrl,
capwap_bio_method_new,
capwap_bio_method_free,
NULL,
};
/* OpenSSL BIO custom data */
struct bio_capwap_data {
int mtu;
struct sockaddr_storage peer;
struct capwap_dtls* dtls;
capwap_bio_send send;
void* param;
};
/* */
static BIO* capwap_bio_new() {
BIO* result;
result = BIO_new(&bio_methods_memory);
if (result) {
memset(result->ptr, 0, sizeof(struct bio_capwap_data));
}
return result;
}
/* */
static int capwap_bio_method_new(BIO* bio) {
bio->init = 1;
bio->num = 0;
bio->flags = 0;
bio->ptr = (char*)capwap_alloc(sizeof(struct bio_capwap_data));
return 1;
}
/* */
static int capwap_bio_method_free(BIO* bio) {
if (bio == NULL) {
return 0;
} else if (bio->ptr) {
capwap_free(bio->ptr);
}
return 1;
}
/* */
static int capwap_bio_method_puts(BIO* bio, const char* str) {
return capwap_bio_method_write(bio, str, strlen(str));
}
/* */
static int capwap_bio_method_read(BIO* bio, char* str, int length) {
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
struct capwap_dtls_header* dtlspreamble;
int size;
/* Check read packet */
if ((data->dtls->length < sizeof(struct capwap_dtls_header)) || !data->dtls->buffer) {
if (!data->dtls->length && !data->dtls->buffer) {
BIO_set_retry_read(bio); /* Notify empty buffer */
}
return -1;
}
/* Check DTLS Capwap Preamble */
dtlspreamble = (struct capwap_dtls_header*)data->dtls->buffer;
if ((dtlspreamble->preamble.version != CAPWAP_PROTOCOL_VERSION) || (dtlspreamble->preamble.type != CAPWAP_PREAMBLE_DTLS_HEADER)) {
capwap_logging_debug("Wrong DTLS Capwap Preamble");
return -1; /* Wrong DTLS Capwap Preamble */
}
/* */
size = data->dtls->length - sizeof(struct capwap_dtls_header);
data->dtls->length = 0;
data->dtls->buffer += sizeof(struct capwap_dtls_header);
if (size > length) {
data->dtls->buffer = NULL;
return -1;
}
/* Copy DTLS packet */
memcpy(str, data->dtls->buffer, size);
data->dtls->buffer = NULL;
return size;
}
/* */
static int capwap_bio_method_write(BIO* bio, const char* str, int length) {
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
char buffer[CAPWAP_MAX_PACKET_SIZE];
struct capwap_dtls_header* dtlspreamble = (struct capwap_dtls_header*)&buffer[0];
/* Check for maxium size of packet */
if (length > (CAPWAP_MAX_PACKET_SIZE - sizeof(struct capwap_dtls_header))) {
return -1;
}
/* Create DTLS Capwap Preamble */
dtlspreamble->preamble.version = CAPWAP_PROTOCOL_VERSION;
dtlspreamble->preamble.type = CAPWAP_PREAMBLE_DTLS_HEADER;
dtlspreamble->reserved1 = dtlspreamble->reserved2 = dtlspreamble->reserved3 = 0;
memcpy(&buffer[0] + sizeof(struct capwap_dtls_header), str, length);
/* Send packet */
if (!data->send(data->dtls, buffer, length + sizeof(struct capwap_dtls_header), data->param)) {
return -1;
}
/* Don't return size of DTLS Capwap Preamble */
return length;
}
/* */
static long capwap_bio_method_ctrl(BIO* bio, int cmd, long num, void* ptr) {
long result = 1;
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
switch (cmd) {
case BIO_CTRL_RESET: {
result = 0;
break;
}
case BIO_CTRL_EOF: {
result = 0;
break;
}
case BIO_CTRL_INFO: {
result = 0;
break;
}
case BIO_CTRL_GET_CLOSE: {
result = bio->shutdown;
break;
}
case BIO_CTRL_SET_CLOSE: {
bio->shutdown = (int)num;
break;
}
case BIO_CTRL_WPENDING:
case BIO_CTRL_PENDING: {
result = 0;
break;
}
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH: {
result = 1;
break;
}
case BIO_CTRL_PUSH: {
result = 0;
break;
}
case BIO_CTRL_POP: {
result = 0;
break;
}
case BIO_CTRL_DGRAM_QUERY_MTU: {
data->mtu = CAPWAP_DTLS_MTU_SIZE;
result = data->mtu;
break;
}
case BIO_CTRL_DGRAM_GET_MTU: {
result = data->mtu;
break;
}
case BIO_CTRL_DGRAM_SET_MTU: {
data->mtu = (int)num;
result = data->mtu;
break;
}
case BIO_CTRL_DGRAM_SET_PEER: {
memcpy(&data->peer, ptr, sizeof(struct sockaddr_storage));
break;
}
case BIO_CTRL_DGRAM_GET_PEER: {
memcpy(ptr, &data->peer, sizeof(struct sockaddr_storage));
break;
}
case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: {
break;
}
default: {
result = 0;
break;
}
}
return result;
}
/* */
int capwap_crypt_init() {
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
return 1;
}
/* */
void capwap_crypt_free() {
ERR_remove_state(0);
ERR_free_strings();
ENGINE_cleanup();
EVP_cleanup();
CONF_modules_finish();
CONF_modules_free();
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
sk_SSL_COMP_free (SSL_COMP_get_compression_methods());
}
/* */
static int check_passwd(char* buffer, int size, int rwflag, void* userdata) {
int length;
struct capwap_dtls_context* dtlscontext = (struct capwap_dtls_context*)userdata;
ASSERT(dtlscontext != NULL);
ASSERT(dtlscontext->mode == CAPWAP_DTLS_MODE_CERTIFICATE);
ASSERT(dtlscontext->cert.pwdprivatekey != NULL);
length = strlen(dtlscontext->cert.pwdprivatekey);
if (!buffer || (size < (length + 1))) {
return 0;
}
strcpy(buffer, dtlscontext->cert.pwdprivatekey);
return length;
}
/* */
static int verify_certificate(int ok, X509_STORE_CTX* ctx) {
int err;
int depth;
X509* err_cert;
char buf[256];
int preverify_ok = 1;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
X509_verify_cert_error_string(err);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
if (depth > CAPWAP_DTLS_CERT_VERIFY_DEPTH) {
preverify_ok = 0;
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
X509_STORE_CTX_set_error(ctx, err);
}
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
}
return preverify_ok;
}
static int create_cookie(SSL* ssl, unsigned char* cookie, unsigned int* cookie_len) {
int length;
unsigned char* buffer;
struct sockaddr_storage peer;
struct capwap_app_data* appdata;
/* */
appdata = (struct capwap_app_data*)SSL_get_app_data(ssl);
if (!appdata) {
return 0;
}
/* Read peer information */
BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
/* Create buffer with peer's address and port */
if (peer.ss_family == AF_INET) {
length = sizeof(struct in_addr) + sizeof(in_port_t);
} else if (peer.ss_family == AF_INET6) {
length = sizeof(struct in6_addr) + sizeof(in_port_t);
} else {
return 0;
}
/* */
buffer = capwap_alloc(length);
if (!buffer) {
capwap_outofmemory();
}
if (peer.ss_family == AF_INET) {
struct sockaddr_in* peeripv4 = (struct sockaddr_in*)&peer;
memcpy(buffer, &peeripv4->sin_port, sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t), &peeripv4->sin_addr, sizeof(struct in_addr));
} else if (peer.ss_family == AF_INET6) {
struct sockaddr_in6* peeripv6 = (struct sockaddr_in6*)&peer;
memcpy(buffer, &peeripv6->sin6_port, sizeof(in_port_t));
memcpy(buffer + sizeof(in_port_t), &peeripv6->sin6_addr, sizeof(struct in6_addr));
}
/* Calculate HMAC of buffer using the secret */
HMAC(EVP_sha1(), appdata->cookie, CAPWAP_COOKIE_SECRET_LENGTH, buffer, length, cookie, cookie_len);
capwap_free(buffer);
return 1;
}
/* */
static int generate_cookie(SSL* ssl, unsigned char* cookie, unsigned int* cookie_len) {
unsigned int resultlength;
unsigned char result[EVP_MAX_MD_SIZE];
if (!create_cookie(ssl, &result[0], &resultlength)) {
return 0;
}
/* Cookie generated */
memcpy(cookie, result, resultlength);
*cookie_len = resultlength;
return 1;
}
/* */
static int verify_cookie(SSL* ssl, unsigned char* cookie, unsigned int cookie_len) {
unsigned int resultlength;
unsigned char result[EVP_MAX_MD_SIZE];
if (!create_cookie(ssl, &result[0], &resultlength)) {
return 0;
}
/* Check cookie */
if ((cookie_len != resultlength) || (memcmp(result, cookie, resultlength) != 0)) {
return 0;
}
return 1;
}
/* */
int capwap_crypt_createcontext(struct capwap_dtls_context* dtlscontext, struct capwap_dtls_param* param) {
int length;
ASSERT(dtlscontext != NULL);
ASSERT(param != NULL);
memset(dtlscontext, 0, sizeof(struct capwap_dtls_context));
dtlscontext->type = param->type;
dtlscontext->mode = param->mode;
/* Alloc context */
dtlscontext->sslcontext = SSL_CTX_new(((param->type == CAPWAP_DTLS_SERVER) ? DTLSv1_server_method() : DTLSv1_client_method()));
if (!dtlscontext->sslcontext) {
capwap_logging_debug("Error to initialize dtls context");
return 0;
}
if (dtlscontext->mode == CAPWAP_DTLS_MODE_CERTIFICATE) {
/* Check context */
if (!param->cert.filecert || !strlen(param->cert.filecert)) {
capwap_logging_debug("Error, request certificate file");
capwap_crypt_freecontext(dtlscontext);
return 0;
} else if (!param->cert.filekey || !strlen(param->cert.filekey)) {
capwap_logging_debug("Error, request privatekey file");
capwap_crypt_freecontext(dtlscontext);
return 0;
} else if (!param->cert.fileca || !strlen(param->cert.fileca)) {
capwap_logging_debug("Error, request ca file");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
/* Public certificate */
if (!SSL_CTX_use_certificate_file(dtlscontext->sslcontext, param->cert.filecert, SSL_FILETYPE_PEM)) {
capwap_logging_debug("Error to load certificate file");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
/* Passwork decrypt privatekey */
length = (param->cert.pwdprivatekey ? strlen(param->cert.pwdprivatekey) : 0);
dtlscontext->cert.pwdprivatekey = (char*)capwap_alloc(sizeof(char) * (length + 1));
if (length > 0) {
strcpy(dtlscontext->cert.pwdprivatekey, param->cert.pwdprivatekey);
}
dtlscontext->cert.pwdprivatekey[length] = 0;
SSL_CTX_set_default_passwd_cb(dtlscontext->sslcontext, check_passwd);
SSL_CTX_set_default_passwd_cb_userdata(dtlscontext->sslcontext, dtlscontext);
/* Private key */
if (!SSL_CTX_use_PrivateKey_file(dtlscontext->sslcontext, param->cert.filekey, SSL_FILETYPE_PEM)) {
capwap_logging_debug("Error to load private key file");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
if (!SSL_CTX_check_private_key(dtlscontext->sslcontext)) {
capwap_logging_debug("Error to check private key");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
/* Certificate Authority */
if (!SSL_CTX_load_verify_locations(dtlscontext->sslcontext, param->cert.fileca, NULL)) {
capwap_logging_debug("Error to load ca file");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
if (!SSL_CTX_set_default_verify_paths(dtlscontext->sslcontext)) {
capwap_crypt_freecontext(dtlscontext);
return 0;
}
/* Verify certificate callback */
SSL_CTX_set_verify(dtlscontext->sslcontext, ((param->type == CAPWAP_DTLS_SERVER) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_PEER), verify_certificate);
/* Cipher list:
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
*/
if (!SSL_CTX_set_cipher_list(dtlscontext->sslcontext, "AES128-SHA:DHE-RSA-AES128-SHA:AES256-SHA:DHE-RSA-AES256-SHA")) {
capwap_logging_debug("Error to select cipher list");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
} else if (dtlscontext->mode == CAPWAP_DTLS_MODE_PRESHAREDKEY) {
/* TODO */
} else {
capwap_logging_debug("Invalid DTLS mode");
capwap_crypt_freecontext(dtlscontext);
return 0;
}
/* Cookie callback */
RAND_bytes(dtlscontext->cookie, CAPWAP_COOKIE_SECRET_LENGTH);
SSL_CTX_set_cookie_generate_cb(dtlscontext->sslcontext, generate_cookie);
SSL_CTX_set_cookie_verify_cb(dtlscontext->sslcontext, verify_cookie);
/* */
SSL_CTX_set_read_ahead(dtlscontext->sslcontext, 1);
return 1;
}
/* */
void capwap_crypt_freecontext(struct capwap_dtls_context* dtlscontext) {
ASSERT(dtlscontext != NULL);
/* */
if (dtlscontext->mode == CAPWAP_DTLS_MODE_CERTIFICATE) {
if (dtlscontext->cert.pwdprivatekey) {
capwap_free(dtlscontext->cert.pwdprivatekey);
}
}
/* Free context */
if (dtlscontext->sslcontext) {
SSL_CTX_free(dtlscontext->sslcontext);
}
memset(dtlscontext, 0, sizeof(struct capwap_dtls));
}
/* */
int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct capwap_dtls_context* dtlscontext, capwap_bio_send biosend, void* param) {
BIO* bio;
struct capwap_app_data* appdata;
ASSERT(dtls != NULL);
ASSERT(dtlscontext != NULL);
ASSERT(biosend != NULL);
memset(dtls, 0, sizeof(struct capwap_dtls));
/* Create ssl session */
dtls->sslsession = SSL_new(dtlscontext->sslcontext);
if (!dtls->sslsession) {
capwap_logging_debug("Error to initialize dtls session");
return 0;
}
/* Create BIO */
bio = capwap_bio_new();
if (!bio) {
capwap_logging_debug("Error to initialize bio");
capwap_crypt_free(dtls);
return 0;
} else {
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
data->dtls = dtls;
data->send = biosend;
data->param = param;
}
/* Configure BIO */
SSL_set_bio(dtls->sslsession, bio, bio);
/* In server mode enable cookie exchange */
if (dtlscontext->type == CAPWAP_DTLS_SERVER) {
SSL_set_options(dtls->sslsession, SSL_OP_COOKIE_EXCHANGE);
}
/* Set static MTU size */
SSL_set_options(dtls->sslsession, SSL_OP_NO_QUERY_MTU);
SSL_set_mtu(dtls->sslsession, CAPWAP_DTLS_MTU_SIZE);
/* */
SSL_set_verify_depth(dtls->sslsession, CAPWAP_DTLS_CERT_VERIFY_DEPTH + 1);
/* */
SSL_set_read_ahead(dtls->sslsession, 1);
if (dtlscontext->type == CAPWAP_DTLS_SERVER) {
SSL_set_accept_state(dtls->sslsession);
} else {
SSL_set_connect_state(dtls->sslsession);
}
/* SSL session app data */
appdata = (struct capwap_app_data*)capwap_alloc(sizeof(struct capwap_app_data));
if (!appdata) {
capwap_outofmemory();
}
appdata->cookie = &dtlscontext->cookie[0];
SSL_set_app_data(dtls->sslsession, (void*)appdata);
/* */
dtls->action = CAPWAP_DTLS_ACTION_NONE;
dtls->session = sessiontype;
dtls->enable = 1;
return 1;
}
/* */
static int capwap_crypt_handshake(struct capwap_dtls* dtls) {
int result;
ASSERT(dtls != NULL);
ASSERT(dtls->enable != 0);
ASSERT((dtls->action == CAPWAP_DTLS_ACTION_NONE) || (dtls->action == CAPWAP_DTLS_ACTION_HANDSHAKE));
ERR_clear_error();
result = SSL_do_handshake(dtls->sslsession);
if (result <= 0) {
result = SSL_get_error(dtls->sslsession, result);
if ((result == SSL_ERROR_WANT_READ) || (result == SSL_ERROR_WANT_WRITE)) {
/* Incomplete handshake */
dtls->action = CAPWAP_DTLS_ACTION_HANDSHAKE;
return CAPWAP_HANDSHAKE_CONTINUE;
}
/* Handshake error */
dtls->action = CAPWAP_DTLS_ACTION_ERROR;
return CAPWAP_HANDSHAKE_ERROR;
}
/* Check certificate */
result = SSL_get_verify_result(dtls->sslsession);
if (result != X509_V_OK) {
dtls->action = CAPWAP_DTLS_ACTION_ERROR;
return CAPWAP_HANDSHAKE_ERROR;
}
/* Handshake complete */
dtls->action = CAPWAP_DTLS_ACTION_DATA;
return CAPWAP_HANDSHAKE_COMPLETE;
}
/* */
int capwap_crypt_open(struct capwap_dtls* dtls, struct sockaddr_storage* peeraddr) {
BIO_dgram_set_peer(SSL_get_rbio(dtls->sslsession), peeraddr);
return capwap_crypt_handshake(dtls);
}
/* */
void capwap_crypt_close(struct capwap_dtls* dtls) {
ASSERT(dtls != NULL);
ASSERT(dtls->enable != 0);
if ((dtls->action == CAPWAP_DTLS_ACTION_DATA) || (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
SSL_shutdown(dtls->sslsession);
}
}
/* Change bio send */
void capwap_crypt_change_bio_send(struct capwap_dtls* dtls, capwap_bio_send biosend, void* param) {
BIO* bio;
ASSERT(dtls != NULL);
ASSERT(dtls->enable != 0);
ASSERT(biosend != NULL);
bio = SSL_get_wbio(dtls->sslsession);
if ((bio != NULL) && (bio->ptr != NULL)) {
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
data->send = biosend;
data->param = param;
}
}
/* Change DTLS */
void capwap_crypt_change_dtls(struct capwap_dtls* dtls, struct capwap_dtls* newdtls) {
BIO* bio;
ASSERT(dtls != NULL);
ASSERT(dtls->enable != 0);
ASSERT(newdtls != NULL);
memcpy(newdtls, dtls, sizeof(struct capwap_dtls));
/* Update DTLS into BIO */
bio = SSL_get_rbio(dtls->sslsession);
if ((bio != NULL) && (bio->ptr != NULL)) {
struct bio_capwap_data* data = (struct bio_capwap_data*)bio->ptr;
data->dtls = newdtls;
}
}
/* */
void capwap_crypt_freesession(struct capwap_dtls* dtls) {
ASSERT(dtls != NULL);
/* Free SSL session */
if (dtls->sslsession) {
struct capwap_app_data* appdata = (struct capwap_app_data*)SSL_get_app_data(dtls->sslsession);
if (appdata) {
capwap_free(appdata);
}
SSL_free(dtls->sslsession);
}
memset(dtls, 0, sizeof(struct capwap_dtls));
}
/* TODO: con SSL vengono utilizzati gli indirizzi predefiniti invece quelli specificati nella funzione. Reingegnerizzarla basandosi sul concetto di connessione */
int capwap_crypt_sendto(struct capwap_dtls* dtls, int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr) {
ASSERT(sock >= 0);
ASSERT(buffer != NULL);
ASSERT(size > 0);
ASSERT(sendtoaddr != NULL);
if (!dtls || !dtls->enable) {
return capwap_sendto(sock, buffer, size, sendfromaddr, sendtoaddr);
}
/* Valid DTLS status */
if (dtls->action != CAPWAP_DTLS_ACTION_DATA) {
return 0;
}
ERR_clear_error();
return SSL_write(dtls->sslsession, buffer, size);
}
/* */
int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size, void* plainbuffer, int maxsize) {
int sslerror;
int result = -1;
char* clone = NULL;
ASSERT(dtls != NULL);
ASSERT(dtls->enable != 0);
ASSERT((dtls->action == CAPWAP_DTLS_ACTION_HANDSHAKE) || (dtls->action == CAPWAP_DTLS_ACTION_DATA));
ASSERT(dtls->buffer == NULL);
ASSERT(dtls->length == 0);
ASSERT(encrybuffer != NULL);
ASSERT(size > 0);
ASSERT(maxsize > 0);
/* */
if (!plainbuffer) {
clone = capwap_clone(encrybuffer, size);
}
dtls->buffer = (clone ? clone : encrybuffer);
dtls->length = size;
/* */
if (dtls->action == CAPWAP_DTLS_ACTION_HANDSHAKE) {
if (capwap_crypt_handshake(dtls) == CAPWAP_HANDSHAKE_ERROR) {
capwap_logging_debug("Error in DTLS handshake");
result = CAPWAP_ERROR_CLOSE; /* Error handshake */
} else {
result = CAPWAP_ERROR_AGAIN; /* Don't parsing DTLS packet */
}
} else if (dtls->action == CAPWAP_DTLS_ACTION_DATA) {
ERR_clear_error();
result = SSL_read(dtls->sslsession, (plainbuffer ? plainbuffer : encrybuffer), maxsize);
if (!result) {
int shutdown;
/* Check shutdown status */
shutdown = SSL_get_shutdown(dtls->sslsession);
if (shutdown & SSL_RECEIVED_SHUTDOWN) {
dtls->action = CAPWAP_DTLS_ACTION_SHUTDOWN;
result = CAPWAP_ERROR_SHUTDOWN;
} else {
result = CAPWAP_ERROR_AGAIN;
}
} else if (result < 0) {
/* Check error */
sslerror = SSL_get_error(dtls->sslsession, result);
if ((sslerror == SSL_ERROR_WANT_READ) || (sslerror == SSL_ERROR_WANT_WRITE)) {
result = CAPWAP_ERROR_AGAIN; /* DTLS Renegotiation */
} else {
result = CAPWAP_ERROR_CLOSE;
}
}
}
/* Verify BIO read */
ASSERT(dtls->buffer == NULL);
ASSERT(dtls->length == 0);
/* Free clone */
if (clone) {
capwap_free(clone);
}
return result;
}

108
src/common/capwap_dtls.h Normal file
View File

@ -0,0 +1,108 @@
#ifndef __CAPWAP_DTLS_HEADER__
#define __CAPWAP_DTLS_HEADER__
#include <openssl/ssl.h>
#define CAPWAP_DTLS_CLIENT 0
#define CAPWAP_DTLS_SERVER 1
#define CAPWAP_DTLS_MODE_NONE 0
#define CAPWAP_DTLS_MODE_CERTIFICATE 1
#define CAPWAP_DTLS_MODE_PRESHAREDKEY 2
#define CAPWAP_DTLS_ACTION_NONE 0
#define CAPWAP_DTLS_ACTION_HANDSHAKE 1
#define CAPWAP_DTLS_ACTION_DATA 2
#define CAPWAP_DTLS_ACTION_SHUTDOWN 3
#define CAPWAP_DTLS_ACTION_ERROR 4
#define CAPWAP_HANDSHAKE_ERROR -1
#define CAPWAP_HANDSHAKE_CONTINUE 0
#define CAPWAP_HANDSHAKE_COMPLETE 1
#define CAPWAP_DTLS_CONTROL_SESSION 0
#define CAPWAP_DTLS_DATA_SESSION 1
#define CAPWAP_COOKIE_SECRET_LENGTH 16
#define CAPWAP_ERROR_AGAIN 0
#define CAPWAP_ERROR_SHUTDOWN -1
#define CAPWAP_ERROR_CLOSE -2
struct capwap_dtls_param {
int type;
int mode;
union {
struct {
int dummy; /* TODO */
} presharedkey;
struct {
/* Certificate files */
char* filecert;
char* filekey;
char* fileca;
/* Password for private key */
char* pwdprivatekey;
} cert;
};
};
struct capwap_dtls_context {
int type;
int mode;
SSL_CTX* sslcontext;
/* Cookie */
unsigned char cookie[CAPWAP_COOKIE_SECRET_LENGTH];
union {
struct {
int dummy; /* TODO */
} presharedkey;
struct {
char* pwdprivatekey; /* Password for private key */
} cert;
};
};
struct capwap_dtls {
int enable;
int action;
int session;
SSL* sslsession;
/* Buffer read */
void* buffer;
int length;
};
struct capwap_app_data {
unsigned char* cookie;
};
typedef int(*capwap_bio_send)(struct capwap_dtls* dtls, char* buffer, int length, void* param);
int capwap_crypt_init();
void capwap_crypt_free();
int capwap_crypt_createcontext(struct capwap_dtls_context* dtlscontext, struct capwap_dtls_param* param);
void capwap_crypt_freecontext(struct capwap_dtls_context* dtlscontext);
int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct capwap_dtls_context* dtlscontext, capwap_bio_send biosend, void* param);
void capwap_crypt_freesession(struct capwap_dtls* dtls);
int capwap_crypt_open(struct capwap_dtls* dtls, struct sockaddr_storage* peeraddr);
void capwap_crypt_close(struct capwap_dtls* dtls);
void capwap_crypt_change_bio_send(struct capwap_dtls* dtls, capwap_bio_send biosend, void* param);
void capwap_crypt_change_dtls(struct capwap_dtls* dtls, struct capwap_dtls* newdtls);
int capwap_crypt_sendto(struct capwap_dtls* dtls, int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr);
int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size, void* plainbuffer, int maxsize);
#endif /* __CAPWAP_DTLS_HEADER__ */

1373
src/common/capwap_element.c Normal file

File diff suppressed because it is too large Load Diff

288
src/common/capwap_element.h Normal file
View File

@ -0,0 +1,288 @@
#ifndef __CAPWAP_ELEMENT_HEADER__
#define __CAPWAP_ELEMENT_HEADER__
#include "capwap_array.h"
#include "capwap_list.h"
/* Standard message elements 1 -> 52 (1 - 1023) */
#define CAPWAP_MESSAGE_ELEMENTS_START 1
#define CAPWAP_MESSAGE_ELEMENTS_STOP 53
#define CAPWAP_MESSAGE_ELEMENTS_COUNT ((CAPWAP_MESSAGE_ELEMENTS_STOP - CAPWAP_MESSAGE_ELEMENTS_START) + 1)
#define IS_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_MESSAGE_ELEMENTS_STOP)) ? 1 : 0)
/* 802.11 message elements 1024 -> 1024 (1024 - 2047) */
#define CAPWAP_80211_MESSAGE_ELEMENTS_START 1024
#define CAPWAP_80211_MESSAGE_ELEMENTS_STOP 1048
#define CAPWAP_80211_MESSAGE_ELEMENTS_COUNT ((CAPWAP_80211_MESSAGE_ELEMENTS_STOP - CAPWAP_80211_MESSAGE_ELEMENTS_START) + 1)
#define IS_80211_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_80211_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_80211_MESSAGE_ELEMENTS_STOP)) ? 1 : 0)
/* Message element */
struct capwap_message_element {
unsigned short type;
unsigned short length;
char data[0];
} __attribute__((__packed__));
typedef struct capwap_message_element*(*capwap_create_message_element)(void* data, unsigned long length);
typedef int(*capwap_validate_message_element)(struct capwap_message_element* element);
typedef void*(*capwap_parsing_message_element)(struct capwap_message_element* element);
typedef void(*capwap_free_message_element)(void*);
struct capwap_message_elements_func {
capwap_create_message_element create;
capwap_validate_message_element check;
capwap_parsing_message_element parsing;
capwap_free_message_element free;
};
struct capwap_message_elements_func* capwap_get_message_element(unsigned long code);
/*********************************************************************************************************************/
/* Standard message elements */
#include "capwap_element_acdescriptor.h" /* 00001 */
#include "capwap_element_acipv4list.h" /* 00002 */
#include "capwap_element_acipv6list.h" /* 00003 */
#include "capwap_element_acname.h" /* 00004 */
#include "capwap_element_acnamepriority.h" /* 00005 */
/* 00006 */
/* 00007 */
/* 00008 */
/* Reserved */ /* 00009 */
#include "capwap_element_controlipv4.h" /* 00010 */
#include "capwap_element_controlipv6.h" /* 00011 */
#include "capwap_element_timers.h" /* 00012 */
/* 00013 */
/* 00014 */
/* 00015 */
#include "capwap_element_decrypterrorreportperiod.h" /* 00016 */
/* 00017 */
/* 00018 */
/* Reserved */ /* 00019 */
#include "capwap_element_discoverytype.h" /* 00020 */
/* 00021 */
/* 00022 */
#include "capwap_element_idletimeout.h" /* 00023 */
/* 00024 */
#include "capwap_element_imageidentifier.h" /* 00025 */
/* 00026 */
/* 00027 */
#include "capwap_element_location.h" /* 00028 */
#include "capwap_element_maximumlength.h" /* 00029 */
#include "capwap_element_localipv4.h" /* 00030 */
#include "capwap_element_radioadmstate.h" /* 00031 */
#include "capwap_element_radiooprstate.h" /* 00032 */
#include "capwap_element_resultcode.h" /* 00033 */
#include "capwap_element_returnedmessage.h" /* 00034 */
#include "capwap_element_sessionid.h" /* 00035 */
#include "capwap_element_statisticstimer.h" /* 00036 */
#include "capwap_element_vendorpayload.h" /* 00037 */
#include "capwap_element_wtpboarddata.h" /* 00038 */
#include "capwap_element_wtpdescriptor.h" /* 00039 */
#include "capwap_element_wtpfallback.h" /* 00040 */
#include "capwap_element_wtpframetunnelmode.h" /* 00041 */
/* Reserved */ /* 00042 */
/* Reserved */ /* 00043 */
#include "capwap_element_wtpmactype.h" /* 00044 */
#include "capwap_element_wtpname.h" /* 00045 */
/* Reserved */ /* 00046 */
/* 00047 */
#include "capwap_element_wtprebootstat.h" /* 00048 */
#include "capwap_element_wtpstaticipaddress.h" /* 00049 */
#include "capwap_element_localipv6.h" /* 00050 */
#include "capwap_element_transport.h" /* 00051 */
#include "capwap_element_mtudiscovery.h" /* 00052 */
#include "capwap_element_ecnsupport.h" /* 00053 */
/* IEEE 802.11 message elements */
#include "capwap_element_80211_wtpradioinformation.h" /* 01048 */
/*********************************************************************************************************************/
struct capwap_element_discovery_request {
struct capwap_discoverytype_element* discoverytype;
struct capwap_wtpboarddata_element* wtpboarddata;
struct capwap_wtpdescriptor_element* wtpdescriptor;
struct capwap_wtpframetunnelmode_element* wtpframetunnel;
struct capwap_wtpmactype_element* wtpmactype;
struct capwap_mtudiscovery_element* mtudiscovery;
struct capwap_vendorpayload_element* vendorpayload;
union {
struct {
struct capwap_array* wtpradioinformation;
} ieee80211;
} binding;
};
void capwap_init_element_discovery_request(struct capwap_element_discovery_request* element, unsigned short binding);
int capwap_parsing_element_discovery_request(struct capwap_element_discovery_request* element, struct capwap_list_item* item);
void capwap_free_element_discovery_request(struct capwap_element_discovery_request* element, unsigned short binding);
/* */
struct capwap_element_discovery_response {
struct capwap_acdescriptor_element* acdescriptor;
struct capwap_acname_element* acname;
struct capwap_array* controlipv4;
struct capwap_array* controlipv6;
struct capwap_vendorpayload_element* vendorpayload;
union {
struct {
struct capwap_array* wtpradioinformation;
} ieee80211;
} binding;
};
void capwap_init_element_discovery_response(struct capwap_element_discovery_response* element, unsigned short binding);
int capwap_parsing_element_discovery_response(struct capwap_element_discovery_response* element, struct capwap_list_item* item);
void capwap_free_element_discovery_response(struct capwap_element_discovery_response* element, unsigned short binding);
/* */
struct capwap_element_join_request {
struct capwap_location_element* locationdata;
struct capwap_wtpboarddata_element* wtpboarddata;
struct capwap_wtpdescriptor_element* wtpdescriptor;
struct capwap_wtpname_element* wtpname;
struct capwap_sessionid_element* sessionid;
struct capwap_wtpframetunnelmode_element* wtpframetunnel;
struct capwap_wtpmactype_element* wtpmactype;
struct capwap_ecnsupport_element* ecnsupport;
struct capwap_localipv4_element* localipv4;
struct capwap_localipv6_element* localipv6;
struct capwap_transport_element* trasport;
struct capwap_maximumlength_element* maxiumlength;
struct capwap_wtprebootstat_element* wtprebootstat;
struct capwap_vendorpayload_element* vendorpayload;
union {
struct {
struct capwap_array* wtpradioinformation;
} ieee80211;
} binding;
};
void capwap_init_element_join_request(struct capwap_element_join_request* element, unsigned short binding);
int capwap_parsing_element_join_request(struct capwap_element_join_request* element, struct capwap_list_item* item);
void capwap_free_element_join_request(struct capwap_element_join_request* element, unsigned short binding);
/* */
struct capwap_element_join_response {
struct capwap_resultcode_element* resultcode;
struct capwap_array* returnedmessage;
struct capwap_acdescriptor_element* acdescriptor;
struct capwap_acname_element* acname;
struct capwap_ecnsupport_element* ecnsupport;
struct capwap_array* controlipv4;
struct capwap_array* controlipv6;
struct capwap_localipv4_element* localipv4;
struct capwap_localipv6_element* localipv6;
capwap_acipv4list_element_array* acipv4list;
capwap_acipv6list_element_array* acipv6list;
struct capwap_transport_element* trasport;
struct capwap_imageidentifier_element* imageidentifier;
struct capwap_maximumlength_element* maxiumlength;
struct capwap_vendorpayload_element* vendorpayload;
union {
struct {
struct capwap_array* wtpradioinformation;
} ieee80211;
} binding;
};
void capwap_init_element_join_response(struct capwap_element_join_response* element, unsigned short binding);
int capwap_parsing_element_join_response(struct capwap_element_join_response* element, struct capwap_list_item* item);
void capwap_free_element_join_response(struct capwap_element_join_response* element, unsigned short binding);
/* */
struct capwap_element_configurationstatus_request {
struct capwap_acname_element* acname;
struct capwap_array* radioadmstatus;
struct capwap_statisticstimer_element* statisticstimer;
struct capwap_wtprebootstat_element* wtprebootstat;
struct capwap_array* acnamepriority;
struct capwap_transport_element* trasport;
struct capwap_wtpstaticipaddress_element* wtpstaticipaddress;
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_configurationstatus_request(struct capwap_element_configurationstatus_request* element, unsigned short binding);
int capwap_parsing_element_configurationstatus_request(struct capwap_element_configurationstatus_request* element, struct capwap_list_item* item);
void capwap_free_element_configurationstatus_request(struct capwap_element_configurationstatus_request* element, unsigned short binding);
/* */
struct capwap_element_configurationstatus_response {
struct capwap_timers_element* timers;
struct capwap_array* decrypterrorresultperiod;
struct capwap_idletimeout_element* idletimeout;
struct capwap_wtpfallback_element* wtpfallback;
capwap_acipv4list_element_array* acipv4list;
capwap_acipv6list_element_array* acipv6list;
struct capwap_array* radiooprstatus;
struct capwap_wtpstaticipaddress_element* wtpstaticipaddress;
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_configurationstatus_response(struct capwap_element_configurationstatus_response* element, unsigned short binding);
int capwap_parsing_element_configurationstatus_response(struct capwap_element_configurationstatus_response* element, struct capwap_list_item* item);
void capwap_free_element_configurationstatus_response(struct capwap_element_configurationstatus_response* element, unsigned short binding);
/* */
struct capwap_element_changestateevent_request {
struct capwap_array* radiooprstatus;
struct capwap_resultcode_element* resultcode;
struct capwap_array* returnedmessage;
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_changestateevent_request(struct capwap_element_changestateevent_request* element, unsigned short binding);
int capwap_parsing_element_changestateevent_request(struct capwap_element_changestateevent_request* element, struct capwap_list_item* item);
void capwap_free_element_changestateevent_request(struct capwap_element_changestateevent_request* element, unsigned short binding);
/* */
struct capwap_element_changestateevent_response {
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_changestateevent_response(struct capwap_element_changestateevent_response* element, unsigned short binding);
int capwap_parsing_element_changestateevent_response(struct capwap_element_changestateevent_response* element, struct capwap_list_item* item);
void capwap_free_element_changestateevent_response(struct capwap_element_changestateevent_response* element, unsigned short binding);
/* */
struct capwap_element_echo_request {
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_echo_request(struct capwap_element_echo_request* element, unsigned short binding);
int capwap_parsing_element_echo_request(struct capwap_element_echo_request* element, struct capwap_list_item* item);
void capwap_free_element_echo_request(struct capwap_element_echo_request* element, unsigned short binding);
/* */
struct capwap_element_echo_response {
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_echo_response(struct capwap_element_echo_response* element, unsigned short binding);
int capwap_parsing_element_echo_response(struct capwap_element_echo_response* element, struct capwap_list_item* item);
void capwap_free_element_echo_response(struct capwap_element_echo_response* element, unsigned short binding);
/* */
struct capwap_element_reset_request {
struct capwap_imageidentifier_element* imageidentifier;
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_reset_request(struct capwap_element_reset_request* element, unsigned short binding);
int capwap_parsing_element_reset_request(struct capwap_element_reset_request* element, struct capwap_list_item* item);
void capwap_free_element_reset_request(struct capwap_element_reset_request* element, unsigned short binding);
/* */
struct capwap_element_reset_response {
struct capwap_resultcode_element* resultcode;
struct capwap_vendorpayload_element* vendorpayload;
};
void capwap_init_element_reset_response(struct capwap_element_reset_response* element, unsigned short binding);
int capwap_parsing_element_reset_response(struct capwap_element_reset_response* element, struct capwap_list_item* item);
void capwap_free_element_reset_response(struct capwap_element_reset_response* element, unsigned short binding);
#endif /* __CAPWAP_ELEMENT_HEADER__ */

View File

@ -0,0 +1,88 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Radio ID | Radio Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Radio Type |
+-+-+-+-+-+-+-+-+
Type: 1048 for IEEE 802.11 WTP Radio Information
Length: 5
********************************************************************/
struct capwap_80211_wtpradioinformation_raw_element {
unsigned char radioid;
unsigned long radiotype;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_80211_wtpradioinformation_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_80211_wtpradioinformation_raw_element* dataraw;
struct capwap_80211_wtpradioinformation_element* dataelement = (struct capwap_80211_wtpradioinformation_element*)data;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_80211_wtpradioinformation_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_80211_wtpradioinformation_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_80211_wtpradioinformation_raw_element));
element->type = htons(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION);
element->length = htons(sizeof(struct capwap_80211_wtpradioinformation_raw_element));
dataraw = (struct capwap_80211_wtpradioinformation_raw_element*)element->data;
dataraw->radioid = dataelement->radioid;
dataraw->radiotype = htonl(dataelement->radiotype);
return element;
}
/* */
int capwap_80211_wtpradioinformation_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_80211_wtpradioinformation_element_parsing(struct capwap_message_element* element) {
struct capwap_80211_wtpradioinformation_element* data;
struct capwap_80211_wtpradioinformation_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION);
if (ntohs(element->length) != 5) {
return NULL;
}
dataraw = (struct capwap_80211_wtpradioinformation_raw_element*)element->data;
/* */
data = (struct capwap_80211_wtpradioinformation_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradioinformation_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->radioid = dataraw->radioid;
data->radiotype = ntohl(dataraw->radiotype);
return data;
}
/* */
void capwap_80211_wtpradioinformation_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,27 @@
#ifndef __CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION_HEADER__
#define __CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION_HEADER__
#define CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION 1048
struct capwap_80211_wtpradioinformation_element {
unsigned char radioid;
unsigned long radiotype;
};
#define CAPWAP_RADIO_TYPE_80211N 0x08
#define CAPWAP_RADIO_TYPE_80211G 0x04
#define CAPWAP_RADIO_TYPE_80211A 0x02
#define CAPWAP_RADIO_TYPE_80211B 0x01
struct capwap_message_element* capwap_80211_wtpradioinformation_element_create(void* data, unsigned long length);
int capwap_80211_wtpradioinformation_element_validate(struct capwap_message_element* element);
void* capwap_80211_wtpradioinformation_element_parsing(struct capwap_message_element* element);
void capwap_80211_wtpradioinformation_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_80211_WTPRADIOINFORMATION_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION); \
f->create(x, sizeof(struct capwap_80211_wtpradioinformation_element)); \
})
#endif /* __CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION_HEADER__ */

View File

@ -0,0 +1,199 @@
#include "capwap.h"
#include "capwap_array.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stations | Limit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Active WTPs | Max WTPs |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Security | R-MAC Field | Reserved1 | DTLS Policy |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AC Information Sub-Element...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AC Information Vendor Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AC Information Type | AC Information Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AC Information Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 1 for AC Descriptor
Length: >= 12
********************************************************************/
struct capwap_acdescriptor_raw_element {
unsigned short stations;
unsigned short limit;
unsigned short activewtp;
unsigned short maxwtp;
unsigned char security;
unsigned char rmacfield;
unsigned char reserved;
unsigned char dtlspolicy;
char data[0];
} __attribute__((__packed__));
struct capwap_acdescriptor_raw_desc_subelement {
unsigned long vendor;
unsigned short type;
unsigned short length;
char data[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_acdescriptor_element_create(void* data, unsigned long datalength) {
char* pos;
unsigned long i;
unsigned short length;
struct capwap_message_element* element;
struct capwap_acdescriptor_raw_element* dataraw;
struct capwap_acdescriptor_element* dataelement = (struct capwap_acdescriptor_element*)data;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_acdescriptor_element));
ASSERT(dataelement->descsubelement != NULL);
/* Calc length packet */
length = sizeof(struct capwap_acdescriptor_raw_element);
for (i = 0; i < dataelement->descsubelement->count; i++) {
struct capwap_acdescriptor_desc_subelement* desc = (struct capwap_acdescriptor_desc_subelement*)capwap_array_get_item_pointer(dataelement->descsubelement, i);
length += sizeof(struct capwap_acdescriptor_raw_desc_subelement) + desc->length;
}
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + length);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + length);
element->type = htons(CAPWAP_ELEMENT_ACDESCRIPTION);
element->length = htons(length);
/* Descriptor */
dataraw = (struct capwap_acdescriptor_raw_element*)element->data;
dataraw->stations = htons(dataelement->station);
dataraw->limit = htons(dataelement->stationlimit);
dataraw->activewtp = htons(dataelement->wtp);
dataraw->maxwtp = htons(dataelement->wtplimit);
dataraw->security = dataelement->security;
dataraw->rmacfield = dataelement->rmacfield;
dataraw->dtlspolicy = dataelement->dtlspolicy;
/* Descriptor Sub-Element */
pos = dataraw->data;
for (i = 0; i < dataelement->descsubelement->count; i++) {
struct capwap_acdescriptor_raw_desc_subelement* descraw = (struct capwap_acdescriptor_raw_desc_subelement*)pos;
struct capwap_acdescriptor_desc_subelement* desc = (struct capwap_acdescriptor_desc_subelement*)capwap_array_get_item_pointer(dataelement->descsubelement, i);
descraw->vendor = htonl(desc->vendor);
descraw->type = htons(desc->type);
descraw->length = htons(desc->length);
memcpy(descraw->data, desc->data, desc->length);
pos += sizeof(struct capwap_acdescriptor_raw_desc_subelement) + desc->length;
}
return element;
}
/* */
int capwap_acdescriptor_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_acdescriptor_element_parsing(struct capwap_message_element* element) {
unsigned char i;
long length;
char* pos;
struct capwap_acdescriptor_element* data;
struct capwap_acdescriptor_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ACDESCRIPTION);
length = (long)ntohs(element->length);
if (length < 12) {
capwap_logging_debug("Invalid AC Descriptor element");
return NULL;
}
/* */
dataraw = (struct capwap_acdescriptor_raw_element*)element->data;
if ((dataraw->stations > dataraw->limit) || (dataraw->activewtp > dataraw->maxwtp)) {
capwap_logging_debug("Invalid AC Descriptor element");
return NULL;
}
/* */
data = (struct capwap_acdescriptor_element*)capwap_alloc(sizeof(struct capwap_acdescriptor_element));
if (!data) {
capwap_outofmemory();
}
data->descsubelement = capwap_array_create(sizeof(struct capwap_acdescriptor_desc_subelement), 0);
/* */
data->station = htons(dataraw->stations);
data->stationlimit = htons(dataraw->limit);
data->wtp = htons(dataraw->activewtp);
data->wtplimit = htons(dataraw->maxwtp);
data->security = dataraw->security;
data->rmacfield = dataraw->rmacfield;
data->dtlspolicy = dataraw->dtlspolicy;
pos = dataraw->data;
length -= sizeof(struct capwap_acdescriptor_raw_element);
/* Description Subelement */
i = 0;
while (length > 0) {
struct capwap_acdescriptor_desc_subelement* desc = (struct capwap_acdescriptor_desc_subelement*)capwap_array_get_item_pointer(data->descsubelement, i);
struct capwap_acdescriptor_raw_desc_subelement* descraw = (struct capwap_acdescriptor_raw_desc_subelement*)pos;
unsigned short desclength = ntohs(descraw->length);
unsigned short descrawlength = sizeof(struct capwap_acdescriptor_raw_desc_subelement) + desclength;
if ((desclength > CAPWAP_ACDESC_SUBELEMENT_MAXDATA) || (length < descrawlength)) {
capwap_logging_debug("Invalid AC Descriptor element");
capwap_acdescriptor_element_free(data);
return NULL;
}
/* */
desc->vendor = ntohl(descraw->vendor);
desc->type = ntohs(descraw->type);
desc->length = desclength;
memcpy(desc->data, descraw->data, desclength);
/* */
i++;
pos += descrawlength;
length -= descrawlength;
}
return data;
}
/* */
void capwap_acdescriptor_element_free(void* data) {
struct capwap_acdescriptor_element* dataelement = (struct capwap_acdescriptor_element*)data;
ASSERT(dataelement != NULL);
ASSERT(dataelement->descsubelement != NULL);
capwap_array_free(dataelement->descsubelement);
capwap_free(dataelement);
}

View File

@ -0,0 +1,48 @@
#ifndef __CAPWAP_ELEMENT_ACDESCRIPTOR_HEADER__
#define __CAPWAP_ELEMENT_ACDESCRIPTOR_HEADER__
#define CAPWAP_ELEMENT_ACDESCRIPTION 1
#define CAPWAP_ACDESC_SECURITY_PRESHARED_KEY 0x04
#define CAPWAP_ACDESC_SECURITY_X509_CERT 0x02
#define CAPWAP_ACDESC_RMACFIELD_SUPPORTED 1
#define CAPWAP_ACDESC_RMACFIELD_NOTSUPPORTED 2
#define CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED 0x04
#define CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED 0x02
struct capwap_acdescriptor_element {
unsigned short station;
unsigned short stationlimit;
unsigned short wtp;
unsigned short wtplimit;
unsigned char security;
unsigned char rmacfield;
unsigned char dtlspolicy;
struct capwap_array* descsubelement;
};
#define CAPWAP_ACDESC_SUBELEMENT_HARDWAREVERSION 4
#define CAPWAP_ACDESC_SUBELEMENT_SOFTWAREVERSION 5
#define CAPWAP_ACDESC_SUBELEMENT_MAXDATA 1024
struct capwap_acdescriptor_desc_subelement {
unsigned long vendor;
unsigned short type;
unsigned short length;
char data[CAPWAP_ACDESC_SUBELEMENT_MAXDATA];
};
struct capwap_message_element* capwap_acdescriptor_element_create(void* data, unsigned long length);
int capwap_acdescriptor_element_validate(struct capwap_message_element* element);
void* capwap_acdescriptor_element_parsing(struct capwap_message_element* element);
void capwap_acdescriptor_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ACDESCRIPTOR_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ACDESCRIPTION); \
f->create(x, sizeof(struct capwap_acdescriptor_element)); \
})
#endif /* __CAPWAP_ELEMENT_ACDESCRIPTOR_HEADER__ */

View File

@ -0,0 +1,103 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address[] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 2 for AC IPv4 List
Length: >= 4
********************************************************************/
struct capwap_acipv4list_raw_element {
unsigned long address;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_acipv4list_element_create(void* data, unsigned long datalength) {
int i;
int items;
unsigned short sizeitems;
struct capwap_message_element* element;
capwap_acipv4list_element_array* dataarray = (capwap_acipv4list_element_array*)data;
struct capwap_acipv4list_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(capwap_acipv4list_element_array));
items = min(dataarray->count, CAPWAP_ACIPV4LIST_MAX_ELEMENTS);
/* Alloc block of memory */
sizeitems = sizeof(struct capwap_acipv4list_raw_element) * items;
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeitems);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeitems);
element->type = htons(CAPWAP_ELEMENT_ACIPV4LIST);
element->length = htons(sizeitems);
dataraw = (struct capwap_acipv4list_raw_element*)element->data;
for (i = 0; i < items; i++) {
struct capwap_acipv4list_element* dataelement = (struct capwap_acipv4list_element*)capwap_array_get_item_pointer(dataarray, i);
dataraw->address = dataelement->address.s_addr;
/* Next raw item */
dataraw++;
}
return element;
}
/* */
int capwap_acipv4list_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_acipv4list_element_parsing(struct capwap_message_element* element) {
int i;
int items;
unsigned short length;
capwap_acipv4list_element_array* data;
struct capwap_acipv4list_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ACIPV4LIST);
length = ntohs(element->length);
if ((length > 0) && ((length % sizeof(struct capwap_acipv4list_raw_element)) != 0)) {
return NULL;
}
/* */
items = length / sizeof(struct capwap_acipv4list_raw_element);
data = (capwap_acipv4list_element_array*)capwap_array_create(sizeof(struct capwap_acipv4list_element), items);
/* */
dataraw = (struct capwap_acipv4list_raw_element*)element->data;
for (i = 0; i < items; i++) {
struct capwap_acipv4list_element* dataelement = (struct capwap_acipv4list_element*)capwap_array_get_item_pointer(data, i);
dataelement->address.s_addr = dataraw->address;
/* Next raw item */
dataraw++;
}
return data;
}
/* */
void capwap_acipv4list_element_free(void* data) {
ASSERT(data != NULL);
capwap_array_free((capwap_acipv4list_element_array*)data);
}

View File

@ -0,0 +1,25 @@
#ifndef __CAPWAP_ELEMENT_ACIPV4LIST_HEADER__
#define __CAPWAP_ELEMENT_ACIPV4LIST_HEADER__
#define CAPWAP_ELEMENT_ACIPV4LIST 2
#define CAPWAP_ACIPV4LIST_MAX_ELEMENTS 1024
typedef struct capwap_array capwap_acipv4list_element_array;
struct capwap_acipv4list_element {
struct in_addr address;
};
struct capwap_message_element* capwap_acipv4list_element_create(void* data, unsigned long datalength);
int capwap_acipv4list_element_validate(struct capwap_message_element* element);
void* capwap_acipv4list_element_parsing(struct capwap_message_element* element);
void capwap_acipv4list_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ACIPV4LIST_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ACIPV4LIST); \
f->create(x, sizeof(capwap_acipv4list_element_array)); \
})
#endif /* __CAPWAP_ELEMENT_ACIPV4LIST_HEADER__ */

View File

@ -0,0 +1,109 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 3 for AC IPV6 List
Length: >= 16
********************************************************************/
struct capwap_acipv6list_raw_element {
unsigned long address[4];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_acipv6list_element_create(void* data, unsigned long datalength) {
int i;
int items;
unsigned short sizeitems;
struct capwap_message_element* element;
capwap_acipv6list_element_array* dataarray = (capwap_acipv6list_element_array*)data;
struct capwap_acipv6list_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(capwap_acipv6list_element_array));
items = min(dataarray->count, CAPWAP_ACIPV6LIST_MAX_ELEMENTS);
/* Alloc block of memory */
sizeitems = sizeof(struct capwap_acipv6list_raw_element) * items;
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeitems);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeitems);
element->type = htons(CAPWAP_ELEMENT_ACIPV6LIST);
element->length = htons(sizeitems);
dataraw = (struct capwap_acipv6list_raw_element*)element->data;
for (i = 0; i < items; i++) {
struct capwap_acipv6list_element* dataelement = (struct capwap_acipv6list_element*)capwap_array_get_item_pointer(dataarray, i);
memcpy(dataraw->address, dataelement->address.s6_addr32, sizeof(unsigned long) * 4);
/* Next raw item */
dataraw++;
}
return element;
}
/* */
int capwap_acipv6list_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_acipv6list_element_parsing(struct capwap_message_element* element) {
int i;
int items;
unsigned short length;
capwap_acipv6list_element_array* data;
struct capwap_acipv6list_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ACIPV6LIST);
length = ntohs(element->length);
if ((length > 0) && ((length % sizeof(struct capwap_acipv6list_raw_element)) != 0)) {
return NULL;
}
/* */
items = length / sizeof(struct capwap_acipv6list_raw_element);
data = (capwap_acipv6list_element_array*)capwap_array_create(sizeof(struct capwap_acipv6list_element), items);
/* */
dataraw = (struct capwap_acipv6list_raw_element*)element->data;
for (i = 0; i < items; i++) {
struct capwap_acipv6list_element* dataelement = (struct capwap_acipv6list_element*)capwap_array_get_item_pointer(data, i);
memcpy(dataelement->address.s6_addr32, dataraw->address, sizeof(unsigned long) * 4);
/* Next raw item */
dataraw++;
}
return data;
}
/* */
void capwap_acipv6list_element_free(void* data) {
ASSERT(data != NULL);
capwap_array_free((capwap_acipv6list_element_array*)data);
}

View File

@ -0,0 +1,25 @@
#ifndef __CAPWAP_ELEMENT_ACIPV6LIST_HEADER__
#define __CAPWAP_ELEMENT_ACIPV6LIST_HEADER__
#define CAPWAP_ELEMENT_ACIPV6LIST 3
#define CAPWAP_ACIPV6LIST_MAX_ELEMENTS 1024
typedef struct capwap_array capwap_acipv6list_element_array;
struct capwap_acipv6list_element {
struct in6_addr address;
};
struct capwap_message_element* capwap_acipv6list_element_create(void* data, unsigned long datalength);
int capwap_acipv6list_element_validate(struct capwap_message_element* element);
void* capwap_acipv6list_element_parsing(struct capwap_message_element* element);
void capwap_acipv6list_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ACIPV6LIST_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ACIPV6LIST); \
f->create(x, sizeof(capwap_acipv6list_element_array)); \
})
#endif /* __CAPWAP_ELEMENT_ACIPV6LIST_HEADER__ */

View File

@ -0,0 +1,86 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| Name ...
+-+-+-+-+-+-+-+-+
Type: 4 for AC Name
Length: >= 1
********************************************************************/
struct capwap_acname_raw_element {
char name[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_acname_element_create(void* data, unsigned long datalength) {
unsigned short namelength;
struct capwap_message_element* element;
struct capwap_acname_raw_element* dataraw;
struct capwap_acname_element* dataelement = (struct capwap_acname_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_acname_element));
/* Alloc block of memory */
namelength = strlen(dataelement->name);
element = capwap_alloc(sizeof(struct capwap_message_element) + namelength);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + namelength);
element->type = htons(CAPWAP_ELEMENT_ACNAME);
element->length = htons(namelength);
dataraw = (struct capwap_acname_raw_element*)element->data;
memcpy(&dataraw->name[0], &dataelement->name[0], namelength);
return element;
}
/* */
int capwap_acname_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_acname_element_parsing(struct capwap_message_element* element) {
unsigned short namelength;
struct capwap_acname_element* data;
struct capwap_acname_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ACNAME);
namelength = ntohs(element->length);
if (!namelength || (namelength > CAPWAP_ACNAME_MAXLENGTH)) {
return NULL;
}
/* */
dataraw = (struct capwap_acname_raw_element*)element->data;
data = (struct capwap_acname_element*)capwap_alloc(sizeof(struct capwap_acname_element));
if (!data) {
capwap_outofmemory();
}
/* */
memcpy(&data->name[0], &dataraw->name[0], namelength);
data->name[namelength] = 0;
return data;
}
/* */
void capwap_acname_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,24 @@
#ifndef __CAPWAP_ELEMENT_ACNAME_HEADER__
#define __CAPWAP_ELEMENT_ACNAME_HEADER__
#define CAPWAP_ELEMENT_ACNAME 4
#define CAPWAP_ACNAME_MAXLENGTH 512
struct capwap_acname_element {
char name[CAPWAP_ACNAME_MAXLENGTH + 1];
};
struct capwap_message_element* capwap_acname_element_create(void* data, unsigned long datalength);
int capwap_acname_element_validate(struct capwap_message_element* element);
void* capwap_acname_element_parsing(struct capwap_message_element* element);
void capwap_acname_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ACNAME_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ACNAME); \
f->create(x, sizeof(struct capwap_acname_element)); \
})
#endif /* __CAPWAP_ELEMENT_ACNAME_HEADER__ */

View File

@ -0,0 +1,91 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Priority | AC Name...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 5 for AC Name with Priority
Length: >= 2
********************************************************************/
struct capwap_acnamepriority_raw_element {
unsigned char priority;
char name[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_acnamepriority_element_create(void* data, unsigned long datalength) {
unsigned short namelength;
struct capwap_message_element* element;
struct capwap_acnamepriority_raw_element* dataraw;
struct capwap_acnamepriority_element* dataelement = (struct capwap_acnamepriority_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_acnamepriority_element));
/* Alloc block of memory */
namelength = strlen(dataelement->name);
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_acnamepriority_raw_element) + namelength);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_acnamepriority_raw_element) + namelength);
element->type = htons(CAPWAP_ELEMENT_ACNAMEPRIORITY);
element->length = htons(sizeof(struct capwap_acnamepriority_raw_element) + namelength);
dataraw = (struct capwap_acnamepriority_raw_element*)element->data;
dataraw->priority = dataelement->priority;
memcpy(&dataraw->name[0], &dataelement->name[0], namelength);
return element;
}
/* */
int capwap_acnamepriority_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_acnamepriority_element_parsing(struct capwap_message_element* element) {
unsigned short namelength;
struct capwap_acnamepriority_element* data;
struct capwap_acnamepriority_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ACNAMEPRIORITY);
namelength = ntohs(element->length) - sizeof(struct capwap_acnamepriority_raw_element);
if (!namelength || (namelength > CAPWAP_ACNAMEPRIORITY_MAXLENGTH)) {
return NULL;
}
/* */
dataraw = (struct capwap_acnamepriority_raw_element*)element->data;
data = (struct capwap_acnamepriority_element*)capwap_alloc(sizeof(struct capwap_acnamepriority_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->priority = dataraw->priority;
memcpy(&data->name[0], &dataraw->name[0], namelength);
data->name[namelength] = 0;
return data;
}
/* */
void capwap_acnamepriority_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,25 @@
#ifndef __CAPWAP_ELEMENT_ACNAMEPRIORITY_HEADER__
#define __CAPWAP_ELEMENT_ACNAMEPRIORITY_HEADER__
#define CAPWAP_ELEMENT_ACNAMEPRIORITY 5
#define CAPWAP_ACNAMEPRIORITY_MAXLENGTH 512
struct capwap_acnamepriority_element {
unsigned char priority;
char name[CAPWAP_ACNAMEPRIORITY_MAXLENGTH + 1];
};
struct capwap_message_element* capwap_acnamepriority_element_create(void* data, unsigned long datalength);
int capwap_acnamepriority_element_validate(struct capwap_message_element* element);
void* capwap_acnamepriority_element_parsing(struct capwap_message_element* element);
void capwap_acnamepriority_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ACNAMEPRIORITY_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ACNAMEPRIORITY); \
f->create(x, sizeof(struct capwap_acnamepriority_element)); \
})
#endif /* __CAPWAP_ELEMENT_ACNAMEPRIORITY_HEADER__ */

View File

@ -0,0 +1,88 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| WTP Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 10 for CAPWAP Control IPv4 Address
Length: 6
********************************************************************/
struct capwap_controlipv4_raw_element {
unsigned long address;
unsigned short wtpcount;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_controlipv4_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_controlipv4_element* dataelement = (struct capwap_controlipv4_element*)data;
struct capwap_controlipv4_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_controlipv4_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_controlipv4_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_controlipv4_raw_element));
element->type = htons(CAPWAP_ELEMENT_CONTROLIPV4);
element->length = htons(sizeof(struct capwap_controlipv4_raw_element));
dataraw = (struct capwap_controlipv4_raw_element*)element->data;
dataraw->address = dataelement->address.s_addr;
dataraw->wtpcount = htons(dataelement->wtpcount);
return element;
}
/* */
int capwap_controlipv4_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_controlipv4_element_parsing(struct capwap_message_element* element) {
struct capwap_controlipv4_element* data;
struct capwap_controlipv4_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_CONTROLIPV4);
if (ntohs(element->length) != sizeof(struct capwap_controlipv4_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_controlipv4_element*)capwap_alloc(sizeof(struct capwap_controlipv4_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_controlipv4_raw_element*)element->data;
data->address.s_addr = dataraw->address;
data->wtpcount = ntohs(dataraw->wtpcount);
return data;
}
/* */
void capwap_controlipv4_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,23 @@
#ifndef __CAPWAP_ELEMENT_CONTROLIPV4_HEADER__
#define __CAPWAP_ELEMENT_CONTROLIPV4_HEADER__
#define CAPWAP_ELEMENT_CONTROLIPV4 10
struct capwap_controlipv4_element {
struct in_addr address;
unsigned short wtpcount;
};
struct capwap_message_element* capwap_controlipv4_element_create(void* data, unsigned long datalength);
int capwap_controlipv4_element_validate(struct capwap_message_element* element);
void* capwap_controlipv4_element_parsing(struct capwap_message_element* element);
void capwap_controlipv4_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_CONTROLIPV4_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_CONTROLIPV4); \
f->create(x, sizeof(struct capwap_controlipv4_element)); \
})
#endif /* __CAPWAP_ELEMENT_CONTROLIPV4_HEADER__ */

View File

@ -0,0 +1,94 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| WTP Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 11 for CAPWAP Control IPv6 Address
Length: 18
********************************************************************/
struct capwap_controlipv6_raw_element {
unsigned long address[4];
unsigned short wtpcount;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_controlipv6_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_controlipv6_element* dataelement = (struct capwap_controlipv6_element*)data;
struct capwap_controlipv6_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_controlipv6_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_controlipv6_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_controlipv6_raw_element));
element->type = htons(CAPWAP_ELEMENT_CONTROLIPV6);
element->length = htons(sizeof(struct capwap_controlipv6_raw_element));
dataraw = (struct capwap_controlipv6_raw_element*)element->data;
memcpy(dataraw->address, dataelement->address.s6_addr32, sizeof(unsigned long) * 4);
dataraw->wtpcount = htons(dataelement->wtpcount);
return element;
}
/* */
int capwap_controlipv6_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_controlipv6_element_parsing(struct capwap_message_element* element) {
struct capwap_controlipv6_element* data;
struct capwap_controlipv6_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_CONTROLIPV6);
if (ntohs(element->length) != sizeof(struct capwap_controlipv6_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_controlipv6_element*)capwap_alloc(sizeof(struct capwap_controlipv6_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_controlipv6_raw_element*)element->data;
memcpy(data->address.s6_addr32, dataraw->address, sizeof(unsigned long) * 4);
data->wtpcount = ntohs(dataraw->wtpcount);
return data;
}
/* */
void capwap_controlipv6_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,23 @@
#ifndef __CAPWAP_ELEMENT_CONTROLIPV6_HEADER__
#define __CAPWAP_ELEMENT_CONTROLIPV6_HEADER__
#define CAPWAP_ELEMENT_CONTROLIPV6 11
struct capwap_controlipv6_element {
struct in6_addr address;
unsigned short wtpcount;
};
struct capwap_message_element* capwap_controlipv6_element_create(void* data, unsigned long datalength);
int capwap_controlipv6_element_validate(struct capwap_message_element* element);
void* capwap_controlipv6_element_parsing(struct capwap_message_element* element);
void capwap_controlipv6_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_CONTROLIPV6_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_CONTROLIPV6); \
f->create(x, sizeof(struct capwap_controlipv6_element)); \
})
#endif /* __CAPWAP_ELEMENT_CONTROLIPV4_HEADER__ */

View File

@ -0,0 +1,86 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Radio ID | Report Interval |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 16 for Decryption Error Report Period
Length: 3
********************************************************************/
struct capwap_decrypterrorreportperiod_raw_element {
unsigned char radioid;
unsigned short interval;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_decrypterrorreportperiod_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_decrypterrorreportperiod_element* dataelement = (struct capwap_decrypterrorreportperiod_element*)data;
struct capwap_decrypterrorreportperiod_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_decrypterrorreportperiod_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_decrypterrorreportperiod_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_decrypterrorreportperiod_raw_element));
element->type = htons(CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD);
element->length = htons(sizeof(struct capwap_decrypterrorreportperiod_raw_element));
dataraw = (struct capwap_decrypterrorreportperiod_raw_element*)element->data;
dataraw->radioid = dataelement->radioid;
dataraw->interval = htons(dataelement->interval);
return element;
}
/* */
int capwap_decrypterrorreportperiod_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_decrypterrorreportperiod_element_parsing(struct capwap_message_element* element) {
struct capwap_decrypterrorreportperiod_element* data;
struct capwap_decrypterrorreportperiod_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD);
if (ntohs(element->length) != sizeof(struct capwap_decrypterrorreportperiod_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_decrypterrorreportperiod_element*)capwap_alloc(sizeof(struct capwap_decrypterrorreportperiod_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_decrypterrorreportperiod_raw_element*)element->data;
data->radioid = dataraw->radioid;
data->interval = ntohs(dataraw->interval);
return data;
}
/* */
void capwap_decrypterrorreportperiod_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,22 @@
#ifndef __CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD_HEADER__
#define __CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD_HEADER__
#define CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD 16
struct capwap_decrypterrorreportperiod_element {
unsigned char radioid;
unsigned short interval;
};
struct capwap_message_element* capwap_decrypterrorreportperiod_element_create(void* data, unsigned long length);
int capwap_decrypterrorreportperiod_element_validate(struct capwap_message_element* element);
void* capwap_decrypterrorreportperiod_element_parsing(struct capwap_message_element* element);
void capwap_decrypterrorreportperiod_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_DECRYPTERRORREPORTPERIOD_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD); \
f->create(x, sizeof(struct capwap_decrypterrorreportperiod_element)); \
})
#endif /* __CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD_HEADER__ */

View File

@ -0,0 +1,75 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| Discovery Type|
+-+-+-+-+-+-+-+-+
Type: 20 for Discovery Type
Length: 1
********************************************************************/
struct capwap_discoverytype_raw_element {
unsigned char type;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_discoverytype_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_discoverytype_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_discoverytype_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_discoverytype_raw_element));
element->type = htons(CAPWAP_ELEMENT_DISCOVERYTYPE);
element->length = htons(sizeof(struct capwap_discoverytype_raw_element));
((struct capwap_discoverytype_raw_element*)element->data)->type = ((struct capwap_discoverytype_element*)data)->type;
return element;
}
/* */
int capwap_discoverytype_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_discoverytype_element_parsing(struct capwap_message_element* element) {
struct capwap_discoverytype_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_DISCOVERYTYPE);
if (ntohs(element->length) != sizeof(struct capwap_discoverytype_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_discoverytype_element*)capwap_alloc(sizeof(struct capwap_discoverytype_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->type = ((struct capwap_discoverytype_raw_element*)element->data)->type;
return data;
}
/* */
void capwap_discoverytype_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,28 @@
#ifndef __CAPWAP_ELEMENT_DISCOVERYTYPE_HEADER__
#define __CAPWAP_ELEMENT_DISCOVERYTYPE_HEADER__
#define CAPWAP_ELEMENT_DISCOVERYTYPE 20
#define CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_UNKNOWN 0
#define CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_STATIC 1
#define CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_DHCP 2
#define CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_DNS 3
#define CAPWAP_ELEMENT_DISCOVERYTYPE_TYPE_ACREFERRAL 4
struct capwap_discoverytype_element {
unsigned char type;
};
struct capwap_message_element* capwap_discoverytype_element_create(void* data, unsigned long datalength);
int capwap_discoverytype_element_validate(struct capwap_message_element* element);
void* capwap_discoverytype_element_parsing(struct capwap_message_element* element);
void capwap_discoverytype_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_DISCOVERYTYPE_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_DISCOVERYTYPE); \
f->create(x, sizeof(struct capwap_discoverytype_element)); \
})
#endif /* __CAPWAP_ELEMENT_DISCOVERYTYPE_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| ECN Support |
+-+-+-+-+-+-+-+-+
Type: 53 for ECN Support
Length: 1
********************************************************************/
struct capwap_ecnsupport_raw_element {
char flag;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_ecnsupport_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_ecnsupport_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_ecnsupport_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_ecnsupport_raw_element));
element->type = htons(CAPWAP_ELEMENT_ECNSUPPORT);
element->length = htons(sizeof(struct capwap_ecnsupport_raw_element));
((struct capwap_ecnsupport_raw_element*)element->data)->flag = ((struct capwap_ecnsupport_element*)data)->flag;
return element;
}
/* */
int capwap_ecnsupport_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_ecnsupport_element_parsing(struct capwap_message_element* element) {
struct capwap_ecnsupport_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_ECNSUPPORT);
if (ntohs(element->length) != sizeof(struct capwap_ecnsupport_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_ecnsupport_element*)capwap_alloc(sizeof(struct capwap_ecnsupport_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->flag = ((struct capwap_ecnsupport_raw_element*)element->data)->flag;
return data;
}
/* */
void capwap_ecnsupport_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,24 @@
#ifndef __CAPWAP_ELEMENT_ECNSUPPORT_HEADER__
#define __CAPWAP_ELEMENT_ECNSUPPORT_HEADER__
#define CAPWAP_ELEMENT_ECNSUPPORT 53
struct capwap_ecnsupport_element {
char flag;
};
#define CAPWAP_LIMITED_ECN_SUPPORT 0
#define CAPWAP_FULL_ECN_SUPPORT 1
struct capwap_message_element* capwap_ecnsupport_element_create(void* data, unsigned long length);
int capwap_ecnsupport_element_validate(struct capwap_message_element* element);
void* capwap_ecnsupport_element_parsing(struct capwap_message_element* element);
void capwap_ecnsupport_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_ECNSUPPORT_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_ECNSUPPORT); \
f->create(x, sizeof(struct capwap_ecnsupport_element)); \
})
#endif /* __CAPWAP_ELEMENT_ECNSUPPORT_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timeout |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 23 for Idle Timeout
Length: 4
********************************************************************/
struct capwap_idletimeout_raw_element {
unsigned long timeout;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_idletimeout_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_idletimeout_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_idletimeout_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_idletimeout_raw_element));
element->type = htons(CAPWAP_ELEMENT_IDLETIMEOUT);
element->length = htons(sizeof(struct capwap_idletimeout_raw_element));
((struct capwap_idletimeout_raw_element*)element->data)->timeout = htonl(((struct capwap_idletimeout_element*)data)->timeout);
return element;
}
/* */
int capwap_idletimeout_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_idletimeout_element_parsing(struct capwap_message_element* element) {
struct capwap_idletimeout_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_IDLETIMEOUT);
if (ntohs(element->length) != sizeof(struct capwap_idletimeout_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_idletimeout_element*)capwap_alloc(sizeof(struct capwap_idletimeout_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->timeout = ntohl(((struct capwap_idletimeout_raw_element*)element->data)->timeout);
return data;
}
/* */
void capwap_idletimeout_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,21 @@
#ifndef __CAPWAP_ELEMENT_IDLETIMEOUT_HEADER__
#define __CAPWAP_ELEMENT_IDLETIMEOUT_HEADER__
#define CAPWAP_ELEMENT_IDLETIMEOUT 23
struct capwap_idletimeout_element {
unsigned long timeout;
};
struct capwap_message_element* capwap_idletimeout_element_create(void* data, unsigned long length);
int capwap_idletimeout_element_validate(struct capwap_message_element* element);
void* capwap_idletimeout_element_parsing(struct capwap_message_element* element);
void capwap_idletimeout_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_IDLETIMEOUT_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_IDLETIMEOUT); \
f->create(x, sizeof(struct capwap_idletimeout_element)); \
})
#endif /* __CAPWAP_ELEMENT_IDLETIMEOUT_HEADER__ */

View File

@ -0,0 +1,93 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Vendor Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 25 for Image Identifier
Length: >= 5
********************************************************************/
struct capwap_imageidentifier_raw_element {
unsigned long vendor;
char name[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_imageidentifier_element_create(void* data, unsigned long datalength) {
unsigned short namelength;
struct capwap_message_element* element;
struct capwap_imageidentifier_raw_element* dataraw;
struct capwap_imageidentifier_element* dataelement = (struct capwap_imageidentifier_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_imageidentifier_element));
/* Alloc block of memory */
namelength = strlen(dataelement->name);
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_imageidentifier_raw_element) + namelength);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_imageidentifier_raw_element) + namelength);
element->type = htons(CAPWAP_ELEMENT_IMAGEIDENTIFIER);
element->length = htons(sizeof(struct capwap_imageidentifier_raw_element) + namelength);
dataraw = (struct capwap_imageidentifier_raw_element*)element->data;
dataraw->vendor = htonl(dataelement->vendor);
memcpy(&dataraw->name[0], &dataelement->name[0], namelength);
return element;
}
/* */
int capwap_imageidentifier_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_imageidentifier_element_parsing(struct capwap_message_element* element) {
unsigned short namelength;
struct capwap_imageidentifier_element* data;
struct capwap_imageidentifier_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_IMAGEIDENTIFIER);
namelength = ntohs(element->length) - sizeof(struct capwap_imageidentifier_raw_element);
if (!namelength || (namelength > CAPWAP_IMAGEIDENTIFIER_MAXLENGTH)) {
return NULL;
}
/* */
dataraw = (struct capwap_imageidentifier_raw_element*)element->data;
data = (struct capwap_imageidentifier_element*)capwap_alloc(sizeof(struct capwap_imageidentifier_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->vendor = ntohl(dataraw->vendor);
memcpy(&data->name[0], &dataraw->name[0], namelength);
data->name[namelength] = 0;
return data;
}
/* */
void capwap_imageidentifier_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,25 @@
#ifndef __CAPWAP_ELEMENT_IMAGEIDENTIFIER_HEADER__
#define __CAPWAP_ELEMENT_IMAGEIDENTIFIER_HEADER__
#define CAPWAP_ELEMENT_IMAGEIDENTIFIER 25
#define CAPWAP_IMAGEIDENTIFIER_MAXLENGTH 1024
struct capwap_imageidentifier_element {
unsigned long vendor;
char name[CAPWAP_IMAGEIDENTIFIER_MAXLENGTH + 1];
};
struct capwap_message_element* capwap_imageidentifier_element_create(void* data, unsigned long datalength);
int capwap_imageidentifier_element_validate(struct capwap_message_element* element);
void* capwap_imageidentifier_element_parsing(struct capwap_message_element* element);
void capwap_imageidentifier_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_IMAGEIDENTIFIER_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_IMAGEIDENTIFIER); \
f->create(x, sizeof(struct capwap_imageidentifier_element)); \
})
#endif /* __CAPWAP_ELEMENT_IMAGEIDENTIFIER_HEADER__ */

View File

@ -0,0 +1,83 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 30 for CAPWAP Local IPv4 Address
Length: 4
********************************************************************/
struct capwap_localipv4_raw_element {
unsigned long address;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_localipv4_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_localipv4_element* dataelement = (struct capwap_localipv4_element*)data;
struct capwap_localipv4_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_localipv4_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_localipv4_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_localipv4_raw_element));
element->type = htons(CAPWAP_ELEMENT_LOCALIPV4);
element->length = htons(sizeof(struct capwap_localipv4_raw_element));
dataraw = (struct capwap_localipv4_raw_element*)element->data;
dataraw->address = dataelement->address.s_addr;
return element;
}
/* */
int capwap_localipv4_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_localipv4_element_parsing(struct capwap_message_element* element) {
struct capwap_localipv4_element* data;
struct capwap_localipv4_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_LOCALIPV4);
if (ntohs(element->length) != sizeof(struct capwap_localipv4_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_localipv4_element*)capwap_alloc(sizeof(struct capwap_localipv4_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_localipv4_raw_element*)element->data;
data->address.s_addr = dataraw->address;
return data;
}
/* */
void capwap_localipv4_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,22 @@
#ifndef __CAPWAP_ELEMENT_LOCALIPV4_HEADER__
#define __CAPWAP_ELEMENT_LOCALIPV4_HEADER__
#define CAPWAP_ELEMENT_LOCALIPV4 30
struct capwap_localipv4_element {
struct in_addr address;
};
struct capwap_message_element* capwap_localipv4_element_create(void* data, unsigned long datalength);
int capwap_localipv4_element_validate(struct capwap_message_element* element);
void* capwap_localipv4_element_parsing(struct capwap_message_element* element);
void capwap_localipv4_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_LOCALIPV4_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_LOCALIPV4); \
f->create(x, sizeof(struct capwap_localipv4_element)); \
})
#endif /* __CAPWAP_ELEMENT_LOCALIPV4_HEADER__ */

View File

@ -0,0 +1,89 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 50 for CAPWAP Local IPv6 Address
Length: 16
********************************************************************/
struct capwap_localipv6_raw_element {
unsigned long address[4];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_localipv6_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_localipv6_element* dataelement = (struct capwap_localipv6_element*)data;
struct capwap_localipv6_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_localipv6_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_localipv6_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_localipv6_raw_element));
element->type = htons(CAPWAP_ELEMENT_LOCALIPV6);
element->length = htons(sizeof(struct capwap_localipv6_raw_element));
dataraw = (struct capwap_localipv6_raw_element*)element->data;
memcpy(dataraw->address, dataelement->address.s6_addr32, sizeof(unsigned long) * 4);
return element;
}
/* */
int capwap_localipv6_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_localipv6_element_parsing(struct capwap_message_element* element) {
struct capwap_localipv6_element* data;
struct capwap_localipv6_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_LOCALIPV6);
if (ntohs(element->length) != sizeof(struct capwap_localipv6_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_localipv6_element*)capwap_alloc(sizeof(struct capwap_localipv6_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_localipv6_raw_element*)element->data;
memcpy(data->address.s6_addr32, dataraw->address, sizeof(unsigned long) * 4);
return data;
}
/* */
void capwap_localipv6_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,22 @@
#ifndef __CAPWAP_ELEMENT_LOCALIPV6_HEADER__
#define __CAPWAP_ELEMENT_LOCALIPV6_HEADER__
#define CAPWAP_ELEMENT_LOCALIPV6 50
struct capwap_localipv6_element {
struct in6_addr address;
};
struct capwap_message_element* capwap_localipv6_element_create(void* data, unsigned long datalength);
int capwap_localipv6_element_validate(struct capwap_message_element* element);
void* capwap_localipv6_element_parsing(struct capwap_message_element* element);
void capwap_localipv6_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_LOCALIPV6_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_LOCALIPV6); \
f->create(x, sizeof(struct capwap_localipv6_element)); \
})
#endif /* __CAPWAP_ELEMENT_CONTROLIPV4_HEADER__ */

View File

@ -0,0 +1,86 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| Location ...
+-+-+-+-+-+-+-+-+
Type: 28 for Location Data
Length: >= 1
********************************************************************/
struct capwap_location_raw_element {
char value[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_location_element_create(void* data, unsigned long datalength) {
unsigned short namelength;
struct capwap_message_element* element;
struct capwap_location_raw_element* dataraw;
struct capwap_location_element* dataelement = (struct capwap_location_element*)data;
ASSERT(data != NULL);
ASSERT(datalength >= sizeof(struct capwap_location_element));
/* Alloc block of memory */
namelength = strlen(dataelement->value);
element = capwap_alloc(sizeof(struct capwap_message_element) + namelength);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + namelength);
element->type = htons(CAPWAP_ELEMENT_LOCATION);
element->length = htons(namelength);
dataraw = (struct capwap_location_raw_element*)element->data;
memcpy(&dataraw->value[0], &dataelement->value[0], namelength);
return element;
}
/* */
int capwap_location_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_location_element_parsing(struct capwap_message_element* element) {
unsigned short namelength;
struct capwap_location_element* data;
struct capwap_location_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_LOCATION);
namelength = ntohs(element->length);
if (!namelength || (namelength > CAPWAP_LOCATION_MAXLENGTH)) {
return NULL;
}
/* */
dataraw = (struct capwap_location_raw_element*)element->data;
data = (struct capwap_location_element*)capwap_alloc(sizeof(struct capwap_location_element));
if (!data) {
capwap_outofmemory();
}
/* */
memcpy(&data->value[0], &dataraw->value[0], namelength);
data->value[namelength] = 0;
return data;
}
/* */
void capwap_location_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,24 @@
#ifndef __CAPWAP_ELEMENT_LOCATION_HEADER__
#define __CAPWAP_ELEMENT_LOCATION_HEADER__
#define CAPWAP_ELEMENT_LOCATION 28
#define CAPWAP_LOCATION_MAXLENGTH 1024
struct capwap_location_element {
char value[CAPWAP_LOCATION_MAXLENGTH + 1];
};
struct capwap_message_element* capwap_location_element_create(void* data, unsigned long datalength);
int capwap_location_element_validate(struct capwap_message_element* element);
void* capwap_location_element_parsing(struct capwap_message_element* element);
void capwap_location_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_LOCATION_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_LOCATION); \
f->create(x, sizeof(struct capwap_location_element)); \
})
#endif /* __CAPWAP_ELEMENT_LOCATION_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Maximum Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 29 for Maximum Message Length
Length: 2
********************************************************************/
struct capwap_maximumlength_raw_element {
unsigned short length;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_maximumlength_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_maximumlength_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_maximumlength_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_maximumlength_raw_element));
element->type = htons(CAPWAP_ELEMENT_MAXIMUMLENGTH);
element->length = htons(sizeof(struct capwap_maximumlength_raw_element));
((struct capwap_maximumlength_raw_element*)element->data)->length = htons(((struct capwap_maximumlength_element*)data)->length);
return element;
}
/* */
int capwap_maximumlength_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_maximumlength_element_parsing(struct capwap_message_element* element) {
struct capwap_maximumlength_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_MAXIMUMLENGTH);
if (ntohs(element->length) != sizeof(struct capwap_maximumlength_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_maximumlength_element*)capwap_alloc(sizeof(struct capwap_maximumlength_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->length = ntohs(((struct capwap_maximumlength_raw_element*)element->data)->length);
return data;
}
/* */
void capwap_maximumlength_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,21 @@
#ifndef __CAPWAP_ELEMENT_MAXIMUMLENGTH_HEADER__
#define __CAPWAP_ELEMENT_MAXIMUMLENGTH_HEADER__
#define CAPWAP_ELEMENT_MAXIMUMLENGTH 29
struct capwap_maximumlength_element {
unsigned short length;
};
struct capwap_message_element* capwap_maximumlength_element_create(void* data, unsigned long length);
int capwap_maximumlength_element_validate(struct capwap_message_element* element);
void* capwap_maximumlength_element_parsing(struct capwap_message_element* element);
void capwap_maximumlength_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_MAXIMUMLENGTH_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_MAXIMUMLENGTH); \
f->create(x, sizeof(struct capwap_maximumlength_element)); \
})
#endif /* __CAPWAP_ELEMENT_MAXIMUMLENGTH_HEADER__ */

View File

@ -0,0 +1,72 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| Padding...
+-+-+-+-+-+-+-+-
Type: 52 for MTU Discovery Padding
Length: variable
********************************************************************/
/* */
struct capwap_message_element* capwap_mtudiscovery_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_mtudiscovery_element* dataelement = (struct capwap_mtudiscovery_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_mtudiscovery_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + dataelement->length);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element));
element->type = htons(CAPWAP_ELEMENT_MTUDISCOVERY);
element->length = htons(dataelement->length);
if (dataelement->length > 0) {
memset(element->data, 0xff, dataelement->length);
}
return element;
}
/* */
int capwap_mtudiscovery_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_mtudiscovery_element_parsing(struct capwap_message_element* element) {
struct capwap_mtudiscovery_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_MTUDISCOVERY);
/* */
data = (struct capwap_mtudiscovery_element*)capwap_alloc(sizeof(struct capwap_mtudiscovery_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->length = ntohs(element->length);
return data;
}
/* */
void capwap_mtudiscovery_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,21 @@
#ifndef __CAPWAP_ELEMENT_MTUDISCOVERY_HEADER__
#define __CAPWAP_ELEMENT_MTUDISCOVERY_HEADER__
#define CAPWAP_ELEMENT_MTUDISCOVERY 52
struct capwap_mtudiscovery_element {
unsigned short length;
};
struct capwap_message_element* capwap_mtudiscovery_element_create(void* data, unsigned long length);
int capwap_mtudiscovery_element_validate(struct capwap_message_element* element);
void* capwap_mtudiscovery_element_parsing(struct capwap_message_element* element);
void capwap_mtudiscovery_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_MTUDISCOVERY_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_MTUDISCOVERY); \
f->create(x, sizeof(struct capwap_mtudiscovery_element)); \
})
#endif /* __CAPWAP_ELEMENT_MTUDISCOVERY_HEADER__ */

View File

@ -0,0 +1,86 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Radio ID | Admin State |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 31 for Radio Administrative State
Length: 2
********************************************************************/
struct capwap_radioadmstate_raw_element {
unsigned char radioid;
unsigned char state;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_radioadmstate_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_radioadmstate_element* dataelement = (struct capwap_radioadmstate_element*)data;
struct capwap_radioadmstate_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_radioadmstate_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_radioadmstate_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_radioadmstate_raw_element));
element->type = htons(CAPWAP_ELEMENT_RADIOADMSTATE);
element->length = htons(sizeof(struct capwap_radioadmstate_raw_element));
dataraw = (struct capwap_radioadmstate_raw_element*)element->data;
dataraw->radioid = dataelement->radioid;
dataraw->state = dataelement->state;
return element;
}
/* */
int capwap_radioadmstate_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_radioadmstate_element_parsing(struct capwap_message_element* element) {
struct capwap_radioadmstate_element* data;
struct capwap_radioadmstate_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_RADIOADMSTATE);
if (ntohs(element->length) != sizeof(struct capwap_radioadmstate_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_radioadmstate_element*)capwap_alloc(sizeof(struct capwap_radioadmstate_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_radioadmstate_raw_element*)element->data;
data->radioid = dataraw->radioid;
data->state = dataraw->state;
return data;
}
/* */
void capwap_radioadmstate_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,25 @@
#ifndef __CAPWAP_ELEMENT_RADIOADMSTATE_HEADER__
#define __CAPWAP_ELEMENT_RADIOADMSTATE_HEADER__
#define CAPWAP_ELEMENT_RADIOADMSTATE 31
struct capwap_radioadmstate_element {
unsigned char radioid;
unsigned char state;
};
#define CAPWAP_RADIO_ADMIN_STATE_ENABLED 1
#define CAPWAP_RADIO_ADMIN_STATE_DISABLED 2
struct capwap_message_element* capwap_radioadmstate_element_create(void* data, unsigned long length);
int capwap_radioadmstate_element_validate(struct capwap_message_element* element);
void* capwap_radioadmstate_element_parsing(struct capwap_message_element* element);
void capwap_radioadmstate_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_RADIOADMSTATE_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_RADIOADMSTATE); \
f->create(x, sizeof(struct capwap_radioadmstate_element)); \
})
#endif /* __CAPWAP_ELEMENT_RADIOADMSTATE_HEADER__ */

View File

@ -0,0 +1,89 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Radio ID | State | Cause |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 32 for Radio Operational State
Length: 3
********************************************************************/
struct capwap_radiooprstate_raw_element {
unsigned char radioid;
unsigned char state;
unsigned char cause;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_radiooprstate_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_radiooprstate_element* dataelement = (struct capwap_radiooprstate_element*)data;
struct capwap_radiooprstate_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_radiooprstate_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_radiooprstate_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_radiooprstate_raw_element));
element->type = htons(CAPWAP_ELEMENT_RADIOOPRSTATE);
element->length = htons(sizeof(struct capwap_radiooprstate_raw_element));
dataraw = (struct capwap_radiooprstate_raw_element*)element->data;
dataraw->radioid = dataelement->radioid;
dataraw->state = dataelement->state;
dataraw->cause = dataelement->cause;
return element;
}
/* */
int capwap_radiooprstate_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_radiooprstate_element_parsing(struct capwap_message_element* element) {
struct capwap_radiooprstate_element* data;
struct capwap_radiooprstate_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_RADIOOPRSTATE);
if (ntohs(element->length) != sizeof(struct capwap_radiooprstate_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_radiooprstate_element*)capwap_alloc(sizeof(struct capwap_radiooprstate_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_radiooprstate_raw_element*)element->data;
data->radioid = dataraw->radioid;
data->state = dataraw->state;
data->cause = dataraw->cause;
return data;
}
/* */
void capwap_radiooprstate_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,31 @@
#ifndef __CAPWAP_ELEMENT_RADIOOPRSTATE_HEADER__
#define __CAPWAP_ELEMENT_RADIOOPRSTATE_HEADER__
#define CAPWAP_ELEMENT_RADIOOPRSTATE 32
struct capwap_radiooprstate_element {
unsigned char radioid;
unsigned char state;
unsigned char cause;
};
#define CAPWAP_RADIO_OPERATIONAL_STATE_ENABLED 1
#define CAPWAP_RADIO_OPERATIONAL_STATE_DISABLED 2
#define CAPWAP_RADIO_OPERATIONAL_CAUSE_NORMAL 0
#define CAPWAP_RADIO_OPERATIONAL_CAUSE_RADIOFAILURE 1
#define CAPWAP_RADIO_OPERATIONAL_CAUSE_SOFTWAREFAILURE 2
#define CAPWAP_RADIO_OPERATIONAL_CAUSE_ADMINSET 3
struct capwap_message_element* capwap_radiooprstate_element_create(void* data, unsigned long length);
int capwap_radiooprstate_element_validate(struct capwap_message_element* element);
void* capwap_radiooprstate_element_parsing(struct capwap_message_element* element);
void capwap_radiooprstate_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_RADIOOPRSTATE_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_RADIOOPRSTATE); \
f->create(x, sizeof(struct capwap_radiooprstate_element)); \
})
#endif /* __CAPWAP_ELEMENT_RADIOOPRSTATE_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Result Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 33 for Result Code
Length: 4
********************************************************************/
struct capwap_resultcode_raw_element {
unsigned long code;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_resultcode_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_resultcode_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_resultcode_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_resultcode_raw_element));
element->type = htons(CAPWAP_ELEMENT_RESULTCODE);
element->length = htons(sizeof(struct capwap_resultcode_raw_element));
((struct capwap_resultcode_raw_element*)element->data)->code = htonl(((struct capwap_resultcode_element*)data)->code);
return element;
}
/* */
int capwap_resultcode_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_resultcode_element_parsing(struct capwap_message_element* element) {
struct capwap_resultcode_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_RESULTCODE);
if (ntohs(element->length) != sizeof(struct capwap_resultcode_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_resultcode_element*)capwap_alloc(sizeof(struct capwap_resultcode_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->code = ntohl(((struct capwap_resultcode_raw_element*)element->data)->code);
return data;
}
/* */
void capwap_resultcode_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,45 @@
#ifndef __CAPWAP_ELEMENT_RESULTCODE_HEADER__
#define __CAPWAP_ELEMENT_RESULTCODE_HEADER__
#define CAPWAP_ELEMENT_RESULTCODE 33
#define CAPWAP_RESULTCODE_SUCCESS 0
#define CAPWAP_RESULTCODE_FAILURE 1
#define CAPWAP_RESULTCODE_SUCCESS_NAT_DETECTED 2
#define CAPWAP_RESULTCODE_JOIN_FAILURE_UNSPECIFIED 3
#define CAPWAP_RESULTCODE_JOIN_FAILURE_RESOURCE_DEPLETION 4
#define CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE 5
#define CAPWAP_RESULTCODE_JOIN_FAILURE_INCORRECT_DATA 6
#define CAPWAP_RESULTCODE_JOIN_FAILURE_ID_ALREADY_IN_USE 7
#define CAPWAP_RESULTCODE_JOIN_FAILURE_WTP_HARDWARE_NOT_SUPPORTED 8
#define CAPWAP_RESULTCODE_JOIN_FAILURE_BINDING_NOT_SUPPORTED 9
#define CAPWAP_RESULTCODE_RESET_FAILURE_UNABLE_TO_RESET 10
#define CAPWAP_RESULTCODE_RESET_FAILURE_FIRMWARE_WRITE_ERROR 11
#define CAPWAP_RESULTCODE_CONF_FAILURE_SERVICE_PROVIDED_ANYHOW 12
#define CAPWAP_RESULTCODE_CONF_FAILURE_SERVICE_NOT_PROVIDED 13
#define CAPWAP_RESULTCODE_IMAGE_ERROR_INVALID_CHECKSUM 14
#define CAPWAP_RESULTCODE_IMAGE_ERROR_INVALID_DATA_LENGTH 15
#define CAPWAP_RESULTCODE_IMAGE_ERROR_OTHER_ERROR 16
#define CAPWAP_RESULTCODE_IMAGE_ERROR_IMAGE_ALREADY_PRESENT 17
#define CAPWAP_RESULTCODE_MSG_UNEXPECTED_INVALID_CURRENT_STATE 18
#define CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST 19
#define CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT 20
#define CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT 21
#define CAPWAP_RESULTCODE_DATA_TRANSFER_ERROR 22
struct capwap_resultcode_element {
unsigned long code;
};
struct capwap_message_element* capwap_resultcode_element_create(void* data, unsigned long length);
int capwap_resultcode_element_validate(struct capwap_message_element* element);
void* capwap_resultcode_element_parsing(struct capwap_message_element* element);
void capwap_resultcode_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_RESULTCODE_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_RESULTCODE); \
f->create(x, sizeof(struct capwap_resultcode_element)); \
})
#endif /* __CAPWAP_ELEMENT_RESULTCODE_HEADER__ */

View File

@ -0,0 +1,93 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason | Length | Message Element...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 34 for Returned Message Element
Length: >= 6
********************************************************************/
struct capwap_returnedmessage_raw_element {
unsigned char reason;
unsigned char length;
char message[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_returnedmessage_element_create(void* data, unsigned long datalength) {
unsigned short length;
struct capwap_message_element* element;
struct capwap_returnedmessage_raw_element* dataraw;
struct capwap_returnedmessage_element* dataelement = (struct capwap_returnedmessage_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_returnedmessage_element));
/* Alloc block of memory */
length = sizeof(struct capwap_returnedmessage_raw_element) + dataelement->length;
element = capwap_alloc(sizeof(struct capwap_message_element) + length);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element));
element->type = htons(CAPWAP_ELEMENT_RETURNEDMESSAGE);
element->length = htons(length);
dataraw = (struct capwap_returnedmessage_raw_element*)element->data;
dataraw->reason = dataelement->reason;
dataraw->length = dataelement->length;
memcpy(&dataraw->message[0], &dataelement->message[0], dataelement->length);
return element;
}
/* */
int capwap_returnedmessage_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_returnedmessage_element_parsing(struct capwap_message_element* element) {
unsigned short length;
struct capwap_returnedmessage_element* data;
struct capwap_returnedmessage_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_RETURNEDMESSAGE);
length = ntohs(element->length) - sizeof(struct capwap_returnedmessage_raw_element);
if (length > CAPWAP_RETURNED_MESSAGE_MAX_LENGTH) {
return NULL;
}
/* */
dataraw = (struct capwap_returnedmessage_raw_element*)element->data;
data = (struct capwap_returnedmessage_element*)capwap_alloc(sizeof(struct capwap_returnedmessage_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->reason = dataraw->reason;
data->length = dataraw->length;
memcpy(&data->message[0], &dataraw->message[0], dataraw->length);
return data;
}
/* */
void capwap_returnedmessage_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,30 @@
#ifndef __CAPWAP_ELEMENT_RETURNEDMESSAGE_HEADER__
#define __CAPWAP_ELEMENT_RETURNEDMESSAGE_HEADER__
#define CAPWAP_ELEMENT_RETURNEDMESSAGE 34
#define CAPWAP_REASON_UNKNOWN_MESSAGE_ELEMENT 1
#define CAPWAP_REASON_UNSUPPORTED_MESSAGE_ELEMENT 2
#define CAPWAP_REASON_UNKNOWN_MESSAGE_ELEMENT_VALUE 3
#define CAPWAP_REASON_UNSUPPORTED_MESSAGE_ELEMENT_VALUE 4
#define CAPWAP_RETURNED_MESSAGE_MAX_LENGTH 255
struct capwap_returnedmessage_element {
unsigned char reason;
unsigned char length;
char message[CAPWAP_RETURNED_MESSAGE_MAX_LENGTH];
};
struct capwap_message_element* capwap_returnedmessage_element_create(void* data, unsigned long length);
int capwap_returnedmessage_element_validate(struct capwap_message_element* element);
void* capwap_returnedmessage_element_parsing(struct capwap_message_element* element);
void capwap_returnedmessage_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_RETURNEDMESSAGE_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_RETURNEDMESSAGE); \
f->create(x, sizeof(struct capwap_returnedmessage_element)); \
})
#endif /* __CAPWAP_ELEMENT_RETURNEDMESSAGE_HEADER__ */

View File

@ -0,0 +1,115 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Session ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Session ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Session ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Session ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 35 for Session ID
Length: 16
********************************************************************/
struct capwap_sessionid_raw_element {
unsigned char id[16];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_sessionid_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_sessionid_raw_element* dataraw;
struct capwap_sessionid_element* dataelement = (struct capwap_sessionid_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_sessionid_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_sessionid_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_sessionid_element));
element->type = htons(CAPWAP_ELEMENT_SESSIONID);
element->length = htons(sizeof(struct capwap_sessionid_element));
dataraw = (struct capwap_sessionid_raw_element*)element->data;
memcpy(&dataraw->id[0], &dataelement->id[0], sizeof(unsigned char) * 16);
return element;
}
/* */
int capwap_sessionid_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_sessionid_element_parsing(struct capwap_message_element* element) {
struct capwap_sessionid_element* data;
struct capwap_sessionid_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_SESSIONID);
if (ntohs(element->length) != sizeof(struct capwap_sessionid_raw_element)) {
return NULL;
}
/* */
dataraw = (struct capwap_sessionid_raw_element*)element->data;
data = (struct capwap_sessionid_element*)capwap_alloc(sizeof(struct capwap_sessionid_element));
if (!data) {
capwap_outofmemory();
}
/* */
memcpy(&data->id[0], &dataraw->id[0], sizeof(unsigned char) * 16);
return data;
}
/* */
void capwap_sessionid_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}
/* */
void capwap_sessionid_generate(struct capwap_sessionid_element* session) {
int i;
ASSERT(session != NULL);
for (i = 0; i < 16; i++) {
session->id[i] = (unsigned char)capwap_get_rand(256);
}
}
/* */
void capwap_sessionid_printf(struct capwap_sessionid_element* session, char* string) {
int i;
char* pos = string;
ASSERT(session != NULL);
ASSERT(string != NULL);
for (i = 0; i < 16; i++) {
sprintf(pos, "%02x", session->id[i]);
pos += 2;
}
*pos = 0;
}

View File

@ -0,0 +1,24 @@
#ifndef __CAPWAP_ELEMENT_SESSIONID_HEADER__
#define __CAPWAP_ELEMENT_SESSIONID_HEADER__
#define CAPWAP_ELEMENT_SESSIONID 35
struct capwap_sessionid_element {
unsigned char id[16];
};
struct capwap_message_element* capwap_sessionid_element_create(void* data, unsigned long datalength);
int capwap_sessionid_element_validate(struct capwap_message_element* element);
void* capwap_sessionid_element_parsing(struct capwap_message_element* element);
void capwap_sessionid_element_free(void* data);
void capwap_sessionid_generate(struct capwap_sessionid_element* session);
void capwap_sessionid_printf(struct capwap_sessionid_element* session, char* string);
/* Helper */
#define CAPWAP_CREATE_SESSIONID_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_SESSIONID); \
f->create(x, sizeof(struct capwap_sessionid_element)); \
})
#endif /* __CAPWAP_ELEMENT_SESSIONID_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Statistics Timer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 36 for Statistics Timer
Length: 2
********************************************************************/
struct capwap_statisticstimer_raw_element {
unsigned short timer;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_statisticstimer_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_statisticstimer_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_statisticstimer_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_statisticstimer_raw_element));
element->type = htons(CAPWAP_ELEMENT_STATISTICSTIMER);
element->length = htons(sizeof(struct capwap_statisticstimer_raw_element));
((struct capwap_statisticstimer_raw_element*)element->data)->timer = htons(((struct capwap_statisticstimer_element*)data)->timer);
return element;
}
/* */
int capwap_statisticstimer_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_statisticstimer_element_parsing(struct capwap_message_element* element) {
struct capwap_statisticstimer_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_STATISTICSTIMER);
if (ntohs(element->length) != sizeof(struct capwap_statisticstimer_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_statisticstimer_element*)capwap_alloc(sizeof(struct capwap_statisticstimer_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->timer = ntohs(((struct capwap_statisticstimer_raw_element*)element->data)->timer);
return data;
}
/* */
void capwap_statisticstimer_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,21 @@
#ifndef __CAPWAP_ELEMENT_STATISTICSTIMER_HEADER__
#define __CAPWAP_ELEMENT_STATISTICSTIMER_HEADER__
#define CAPWAP_ELEMENT_STATISTICSTIMER 36
struct capwap_statisticstimer_element {
unsigned short timer;
};
struct capwap_message_element* capwap_statisticstimer_element_create(void* data, unsigned long length);
int capwap_statisticstimer_element_validate(struct capwap_message_element* element);
void* capwap_statisticstimer_element_parsing(struct capwap_message_element* element);
void capwap_statisticstimer_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_STATISTICSTIMER_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_STATISTICSTIMER); \
f->create(x, sizeof(struct capwap_statisticstimer_element)); \
})
#endif /* __CAPWAP_ELEMENT_STATISTICSTIMER_HEADER__ */

View File

@ -0,0 +1,86 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Discovery | Echo Request |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 12 for CAPWAP Timers
Length: 2
********************************************************************/
struct capwap_timers_raw_element {
unsigned char discovery;
unsigned char echorequest;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_timers_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
struct capwap_timers_element* dataelement = (struct capwap_timers_element*)data;
struct capwap_timers_raw_element* dataraw;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_timers_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_timers_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_timers_raw_element));
element->type = htons(CAPWAP_ELEMENT_TIMERS);
element->length = htons(sizeof(struct capwap_timers_raw_element));
dataraw = (struct capwap_timers_raw_element*)element->data;
dataraw->discovery = dataelement->discovery;
dataraw->echorequest = dataelement->echorequest;
return element;
}
/* */
int capwap_timers_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_timers_element_parsing(struct capwap_message_element* element) {
struct capwap_timers_element* data;
struct capwap_timers_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_TIMERS);
if (ntohs(element->length) != sizeof(struct capwap_timers_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_timers_element*)capwap_alloc(sizeof(struct capwap_timers_element));
if (!data) {
capwap_outofmemory();
}
/* */
dataraw = (struct capwap_timers_raw_element*)element->data;
data->discovery = dataraw->discovery;
data->echorequest = dataraw->echorequest;
return data;
}
/* */
void capwap_timers_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,22 @@
#ifndef __CAPWAP_ELEMENT_TIMERS_HEADER__
#define __CAPWAP_ELEMENT_TIMERS_HEADER__
#define CAPWAP_ELEMENT_TIMERS 12
struct capwap_timers_element {
unsigned char discovery;
unsigned char echorequest;
};
struct capwap_message_element* capwap_timers_element_create(void* data, unsigned long length);
int capwap_timers_element_validate(struct capwap_message_element* element);
void* capwap_timers_element_parsing(struct capwap_message_element* element);
void capwap_timers_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_TIMERS_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_TIMERS); \
f->create(x, sizeof(struct capwap_timers_element)); \
})
#endif /* __CAPWAP_ELEMENT_TIMERS_HEADER__ */

View File

@ -0,0 +1,77 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| Transport |
+-+-+-+-+-+-+-+-+
Type: 51 for CAPWAP Transport Protocol
Length: 1
********************************************************************/
struct capwap_transport_raw_element {
char type;
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_transport_element_create(void* data, unsigned long datalength) {
struct capwap_message_element* element;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_transport_element));
/* Alloc block of memory */
element = capwap_alloc(sizeof(struct capwap_message_element) + sizeof(struct capwap_transport_raw_element));
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + sizeof(struct capwap_transport_raw_element));
element->type = htons(CAPWAP_ELEMENT_TRANSPORT);
element->length = htons(sizeof(struct capwap_transport_raw_element));
((struct capwap_transport_raw_element*)element->data)->type = ((struct capwap_transport_element*)data)->type;
return element;
}
/* */
int capwap_transport_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_transport_element_parsing(struct capwap_message_element* element) {
struct capwap_transport_element* data;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_TRANSPORT);
if (ntohs(element->length) != sizeof(struct capwap_transport_raw_element)) {
return NULL;
}
/* */
data = (struct capwap_transport_element*)capwap_alloc(sizeof(struct capwap_transport_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->type = ((struct capwap_transport_raw_element*)element->data)->type;
return data;
}
/* */
void capwap_transport_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

View File

@ -0,0 +1,24 @@
#ifndef __CAPWAP_ELEMENT_TRANSPORT_HEADER__
#define __CAPWAP_ELEMENT_TRANSPORT_HEADER__
#define CAPWAP_ELEMENT_TRANSPORT 51
struct capwap_transport_element {
char type;
};
#define CAPWAP_UDPLITE_TRANSPORT 1
#define CAPWAP_UDP_TRANSPORT 2
struct capwap_message_element* capwap_transport_element_create(void* data, unsigned long length);
int capwap_transport_element_validate(struct capwap_message_element* element);
void* capwap_transport_element_parsing(struct capwap_message_element* element);
void capwap_transport_element_free(void* data);
/* Helper */
#define CAPWAP_CREATE_TRANSPORT_ELEMENT(x) ({ \
struct capwap_message_elements_func* f = capwap_get_message_element(CAPWAP_ELEMENT_TRANSPORT); \
f->create(x, sizeof(struct capwap_transport_element)); \
})
#endif /* __CAPWAP_ELEMENT_TRANSPORT_HEADER__ */

View File

@ -0,0 +1,99 @@
#include "capwap.h"
#include "capwap_element.h"
/********************************************************************
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Vendor Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Element ID | Data...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type: 37 for Vendor Specific Payload
Length: >= 7
********************************************************************/
struct capwap_vendorpayload_raw_element {
unsigned long vendorid;
unsigned short elementid;
char data[0];
} __attribute__((__packed__));
/* */
struct capwap_message_element* capwap_vendorpayload_element_create(void* data, unsigned long datalength) {
unsigned short elementlength;
struct capwap_message_element* element;
struct capwap_vendorpayload_raw_element* dataraw;
struct capwap_vendorpayload_element* dataelement = (struct capwap_vendorpayload_element*)data;
ASSERT(data != NULL);
ASSERT(datalength == sizeof(struct capwap_vendorpayload_element));
/* */
if (!dataelement->datalength || (dataelement->datalength > CAPWAP_VENDORPAYLOAD_MAXLENGTH)) {
return NULL;
}
/* Alloc block of memory */
elementlength = sizeof(struct capwap_vendorpayload_raw_element) + dataelement->datalength;
element = capwap_alloc(sizeof(struct capwap_message_element) + elementlength);
if (!element) {
capwap_outofmemory();
}
/* Create message element */
memset(element, 0, sizeof(struct capwap_message_element) + elementlength);
element->type = htons(CAPWAP_ELEMENT_VENDORPAYLOAD);
element->length = htons(elementlength);
dataraw = (struct capwap_vendorpayload_raw_element*)element->data;
dataraw->vendorid = htonl(dataelement->vendorid);
dataraw->elementid = htons(dataelement->elementid);
memcpy(&dataraw->data[0], &dataelement->data[0], dataelement->datalength);
return element;
}
/* */
int capwap_vendorpayload_element_validate(struct capwap_message_element* element) {
/* TODO */
return 1;
}
/* */
void* capwap_vendorpayload_element_parsing(struct capwap_message_element* element) {
unsigned short elementlength;
struct capwap_vendorpayload_element* data;
struct capwap_vendorpayload_raw_element* dataraw;
ASSERT(element);
ASSERT(ntohs(element->type) == CAPWAP_ELEMENT_VENDORPAYLOAD);
elementlength = ntohs(element->length);
if (elementlength > sizeof(struct capwap_vendorpayload_raw_element)) {
return NULL;
}
/* */
dataraw = (struct capwap_vendorpayload_raw_element*)element->data;
data = (struct capwap_vendorpayload_element*)capwap_alloc(sizeof(struct capwap_vendorpayload_element));
if (!data) {
capwap_outofmemory();
}
/* */
data->vendorid = ntohl(dataraw->vendorid);
data->elementid = ntohs(dataraw->elementid);
data->datalength = elementlength - sizeof(struct capwap_vendorpayload_element);
memcpy(&data->data[0], &dataraw->data[0], data->datalength);
return data;
}
/* */
void capwap_vendorpayload_element_free(void* data) {
ASSERT(data != NULL);
capwap_free(data);
}

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