The capwap data channel migrated from userspace to kernalspace

This commit is contained in:
vemax78 2014-09-10 21:58:23 +02:00
parent 71006a9121
commit 8d9985fdea
104 changed files with 6967 additions and 4840 deletions

0
AUTHORS Normal file
View File

0
ChangeLog Normal file
View File

View File

@ -1,20 +1,20 @@
SmartCAPWAP -- An Open Source CAPWAP WTP / AC SmartCAPWAP -- An Open Source CAPWAP WTP / AC
Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com> Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
SmartCAPWAP software is available under two distinct licensing models: Open Source and Commercial Licensing. SmartCAPWAP software is available under two distinct licensing models: Open Source and Commercial Licensing.
Under this model users may choose to use SmartCAPWAP under the GNU General Public License or under a Commercial License. Under this model users may choose to use SmartCAPWAP under the GNU General Public License or under a Commercial License.
Please see the relevant section below for information on each type of license. Please see the relevant section below for information on each type of license.
Open Source: Open Source:
In order to use the GNU version of SmartCAPWAP your product must be GPL compliant, In order to use the GNU version of SmartCAPWAP your product must be GPL compliant,
which includes making the source of your entire application available to the public. which includes making the source of your entire application available to the public.
Commercial Licensing: Commercial Licensing:
Businesses and enterprises who wish to incorporate SmartCAPWAP products into proprietary appliances or Businesses and enterprises who wish to incorporate SmartCAPWAP products into proprietary appliances or
other commercial software products for re-distribution must license commercial versions. other commercial software products for re-distribution must license commercial versions.
Licenses are generally issued for one product and include unlimited distribution. Licenses are generally issued for one product and include unlimited distribution.
The use of this license may require the purchase of commercial licenses for third-party libraries. The use of this license may require the purchase of commercial licenses for third-party libraries.

View File

@ -20,15 +20,23 @@
AUTOMAKE_OPTIONS = foreign 1.9 AUTOMAKE_OPTIONS = foreign 1.9
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
MAINTAINERCLEANFILES = \ MAINTAINERCLEANFILES = $(srcdir)/config.log \
config.log config.status \ $(srcdir)/config.status \
$(srcdir)/Makefile.in \ $(srcdir)/Makefile.in \
$(srcdir)/config.h.in $(srcdir)/config.h.in~ $(srcdir)/configure \ $(srcdir)/config.h.in \
$(srcdir)/install-sh $(srcdir)/ltmain.sh $(srcdir)/missing \ $(srcdir)/config.h.in~ \
$(srcdir)/m4/libtool.m4 $(srcdir)/m4/lt~obsolete.m4 \ $(srcdir)/configure \
$(srcdir)/m4/ltoptions.m4 $(srcdir)/m4/ltsugar.m4 \ $(srcdir)/build/install-sh \
$(srcdir)/ltmain.sh \
$(srcdir)/build/missing \
$(srcdir)/m4/libtool.m4 \
$(srcdir)/m4/lt~obsolete.m4 \
$(srcdir)/m4/ltoptions.m4 \
$(srcdir)/m4/ltsugar.m4 \
$(srcdir)/m4/ltversion.m4 \ $(srcdir)/m4/ltversion.m4 \
$(srcdir)/depcomp $(srcdir)/aclocal.m4 \ $(srcdir)/depcomp \
$(srcdir)/config.guess $(srcdir)/config.sub $(srcdir)/aclocal.m4 \
$(srcdir)/build/config.guess \
$(srcdir)/build/config.sub
SUBDIRS = build SUBDIRS = build

0
NEWS Normal file
View File

0
README Normal file
View File

View File

@ -1,31 +1,30 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC # SmartCAPWAP -- An Open Source CAPWAP WTP / AC
# #
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com> # Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING included with this # along with this program (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc., # distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
$(srcdir)/Makefile.in
SUBDIRS =
SUBDIRS =
if BUILD_AC
if BUILD_AC SUBDIRS += ac
SUBDIRS += ac endif
endif
if BUILD_WTP
if BUILD_WTP SUBDIRS += wtp
SUBDIRS += wtp endif
endif

View File

@ -1,109 +1,107 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC # SmartCAPWAP -- An Open Source CAPWAP WTP / AC
# #
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com> # Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING included with this # along with this program (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc., # distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
capwap_SOURCES = \ capwap_SOURCES = $(top_srcdir)/src/common/capwap.c \
$(top_srcdir)/src/common/md5.c \ $(top_srcdir)/src/common/capwap_timeout.c \
$(top_srcdir)/src/common/capwap.c \ $(top_srcdir)/src/common/capwap_network.c \
$(top_srcdir)/src/common/capwap_timeout.c \ $(top_srcdir)/src/common/capwap_protocol.c \
$(top_srcdir)/src/common/capwap_network.c \ $(top_srcdir)/src/common/capwap_logging.c \
$(top_srcdir)/src/common/capwap_protocol.c \ $(top_srcdir)/src/common/capwap_list.c \
$(top_srcdir)/src/common/capwap_logging.c \ $(top_srcdir)/src/common/capwap_array.c \
$(top_srcdir)/src/common/capwap_list.c \ $(top_srcdir)/src/common/capwap_hash.c \
$(top_srcdir)/src/common/capwap_array.c \ $(top_srcdir)/src/common/capwap_dtls.c \
$(top_srcdir)/src/common/capwap_hash.c \ $(top_srcdir)/src/common/capwap_dfa.c \
$(top_srcdir)/src/common/capwap_dtls.c \ $(top_srcdir)/src/common/capwap_element.c \
$(top_srcdir)/src/common/capwap_dfa.c \ $(top_srcdir)/src/common/capwap_element_acdescriptor.c \
$(top_srcdir)/src/common/capwap_element.c \ $(top_srcdir)/src/common/capwap_element_actimestamp.c \
$(top_srcdir)/src/common/capwap_element_acdescriptor.c \ $(top_srcdir)/src/common/capwap_element_addmacacl.c \
$(top_srcdir)/src/common/capwap_element_actimestamp.c \ $(top_srcdir)/src/common/capwap_element_deletemacacl.c \
$(top_srcdir)/src/common/capwap_element_addmacacl.c \ $(top_srcdir)/src/common/capwap_element_addstation.c \
$(top_srcdir)/src/common/capwap_element_deletemacacl.c \ $(top_srcdir)/src/common/capwap_element_deletestation.c \
$(top_srcdir)/src/common/capwap_element_addstation.c \ $(top_srcdir)/src/common/capwap_element_discoverytype.c \
$(top_srcdir)/src/common/capwap_element_deletestation.c \ $(top_srcdir)/src/common/capwap_element_duplicateipv4.c \
$(top_srcdir)/src/common/capwap_element_discoverytype.c \ $(top_srcdir)/src/common/capwap_element_duplicateipv6.c \
$(top_srcdir)/src/common/capwap_element_duplicateipv4.c \ $(top_srcdir)/src/common/capwap_element_datatransferdata.c \
$(top_srcdir)/src/common/capwap_element_duplicateipv6.c \ $(top_srcdir)/src/common/capwap_element_datatransfermode.c \
$(top_srcdir)/src/common/capwap_element_datatransferdata.c \ $(top_srcdir)/src/common/capwap_element_decrypterrorreport.c \
$(top_srcdir)/src/common/capwap_element_datatransfermode.c \ $(top_srcdir)/src/common/capwap_element_imagedata.c \
$(top_srcdir)/src/common/capwap_element_decrypterrorreport.c \ $(top_srcdir)/src/common/capwap_element_imageinfo.c \
$(top_srcdir)/src/common/capwap_element_imagedata.c \ $(top_srcdir)/src/common/capwap_element_initdownload.c \
$(top_srcdir)/src/common/capwap_element_imageinfo.c \ $(top_srcdir)/src/common/capwap_element_wtpboarddata.c \
$(top_srcdir)/src/common/capwap_element_initdownload.c \ $(top_srcdir)/src/common/capwap_element_wtpdescriptor.c \
$(top_srcdir)/src/common/capwap_element_wtpboarddata.c \ $(top_srcdir)/src/common/capwap_element_wtpframetunnelmode.c \
$(top_srcdir)/src/common/capwap_element_wtpdescriptor.c \ $(top_srcdir)/src/common/capwap_element_wtpmactype.c \
$(top_srcdir)/src/common/capwap_element_wtpframetunnelmode.c \ $(top_srcdir)/src/common/capwap_element_acname.c \
$(top_srcdir)/src/common/capwap_element_wtpmactype.c \ $(top_srcdir)/src/common/capwap_element_controlipv4.c \
$(top_srcdir)/src/common/capwap_element_acname.c \ $(top_srcdir)/src/common/capwap_element_controlipv6.c \
$(top_srcdir)/src/common/capwap_element_controlipv4.c \ $(top_srcdir)/src/common/capwap_element_location.c \
$(top_srcdir)/src/common/capwap_element_controlipv6.c \ $(top_srcdir)/src/common/capwap_element_wtpname.c \
$(top_srcdir)/src/common/capwap_element_location.c \ $(top_srcdir)/src/common/capwap_element_sessionid.c \
$(top_srcdir)/src/common/capwap_element_wtpname.c \ $(top_srcdir)/src/common/capwap_element_ecnsupport.c \
$(top_srcdir)/src/common/capwap_element_sessionid.c \ $(top_srcdir)/src/common/capwap_element_localipv4.c \
$(top_srcdir)/src/common/capwap_element_ecnsupport.c \ $(top_srcdir)/src/common/capwap_element_localipv6.c \
$(top_srcdir)/src/common/capwap_element_localipv4.c \ $(top_srcdir)/src/common/capwap_element_transport.c \
$(top_srcdir)/src/common/capwap_element_localipv6.c \ $(top_srcdir)/src/common/capwap_element_mtudiscovery.c \
$(top_srcdir)/src/common/capwap_element_transport.c \ $(top_srcdir)/src/common/capwap_element_vendorpayload.c \
$(top_srcdir)/src/common/capwap_element_mtudiscovery.c \ $(top_srcdir)/src/common/capwap_element_maximumlength.c \
$(top_srcdir)/src/common/capwap_element_vendorpayload.c \ $(top_srcdir)/src/common/capwap_element_wtprebootstat.c \
$(top_srcdir)/src/common/capwap_element_maximumlength.c \ $(top_srcdir)/src/common/capwap_element_wtpradiostat.c \
$(top_srcdir)/src/common/capwap_element_wtprebootstat.c \ $(top_srcdir)/src/common/capwap_element_resultcode.c \
$(top_srcdir)/src/common/capwap_element_wtpradiostat.c \ $(top_srcdir)/src/common/capwap_element_returnedmessage.c \
$(top_srcdir)/src/common/capwap_element_resultcode.c \ $(top_srcdir)/src/common/capwap_element_acipv4list.c \
$(top_srcdir)/src/common/capwap_element_returnedmessage.c \ $(top_srcdir)/src/common/capwap_element_acipv6list.c \
$(top_srcdir)/src/common/capwap_element_acipv4list.c \ $(top_srcdir)/src/common/capwap_element_imageidentifier.c \
$(top_srcdir)/src/common/capwap_element_acipv6list.c \ $(top_srcdir)/src/common/capwap_element_radioadmstate.c \
$(top_srcdir)/src/common/capwap_element_imageidentifier.c \ $(top_srcdir)/src/common/capwap_element_statisticstimer.c \
$(top_srcdir)/src/common/capwap_element_radioadmstate.c \ $(top_srcdir)/src/common/capwap_element_acnamepriority.c \
$(top_srcdir)/src/common/capwap_element_statisticstimer.c \ $(top_srcdir)/src/common/capwap_element_wtpstaticipaddress.c \
$(top_srcdir)/src/common/capwap_element_acnamepriority.c \ $(top_srcdir)/src/common/capwap_element_timers.c \
$(top_srcdir)/src/common/capwap_element_wtpstaticipaddress.c \ $(top_srcdir)/src/common/capwap_element_decrypterrorreportperiod.c \
$(top_srcdir)/src/common/capwap_element_timers.c \ $(top_srcdir)/src/common/capwap_element_idletimeout.c \
$(top_srcdir)/src/common/capwap_element_decrypterrorreportperiod.c \ $(top_srcdir)/src/common/capwap_element_wtpfallback.c \
$(top_srcdir)/src/common/capwap_element_idletimeout.c \ $(top_srcdir)/src/common/capwap_element_radiooprstate.c \
$(top_srcdir)/src/common/capwap_element_wtpfallback.c \ $(top_srcdir)/src/common/capwap_element_80211_addwlan.c \
$(top_srcdir)/src/common/capwap_element_radiooprstate.c \ $(top_srcdir)/src/common/capwap_element_80211_antenna.c \
$(top_srcdir)/src/common/capwap_element_80211_addwlan.c \ $(top_srcdir)/src/common/capwap_element_80211_assignbssid.c \
$(top_srcdir)/src/common/capwap_element_80211_antenna.c \ $(top_srcdir)/src/common/capwap_element_80211_deletewlan.c \
$(top_srcdir)/src/common/capwap_element_80211_assignbssid.c \ $(top_srcdir)/src/common/capwap_element_80211_directsequencecontrol.c \
$(top_srcdir)/src/common/capwap_element_80211_deletewlan.c \ $(top_srcdir)/src/common/capwap_element_80211_ie.c \
$(top_srcdir)/src/common/capwap_element_80211_directsequencecontrol.c \ $(top_srcdir)/src/common/capwap_element_80211_macoperation.c \
$(top_srcdir)/src/common/capwap_element_80211_ie.c \ $(top_srcdir)/src/common/capwap_element_80211_miccountermeasures.c \
$(top_srcdir)/src/common/capwap_element_80211_macoperation.c \ $(top_srcdir)/src/common/capwap_element_80211_multidomaincapability.c \
$(top_srcdir)/src/common/capwap_element_80211_miccountermeasures.c \ $(top_srcdir)/src/common/capwap_element_80211_ofdmcontrol.c \
$(top_srcdir)/src/common/capwap_element_80211_multidomaincapability.c \ $(top_srcdir)/src/common/capwap_element_80211_rateset.c \
$(top_srcdir)/src/common/capwap_element_80211_ofdmcontrol.c \ $(top_srcdir)/src/common/capwap_element_80211_rsnaerrorreport.c \
$(top_srcdir)/src/common/capwap_element_80211_rateset.c \ $(top_srcdir)/src/common/capwap_element_80211_station.c \
$(top_srcdir)/src/common/capwap_element_80211_rsnaerrorreport.c \ $(top_srcdir)/src/common/capwap_element_80211_stationqos.c \
$(top_srcdir)/src/common/capwap_element_80211_station.c \ $(top_srcdir)/src/common/capwap_element_80211_stationkey.c \
$(top_srcdir)/src/common/capwap_element_80211_stationqos.c \ $(top_srcdir)/src/common/capwap_element_80211_statistics.c \
$(top_srcdir)/src/common/capwap_element_80211_stationkey.c \ $(top_srcdir)/src/common/capwap_element_80211_supportedrates.c \
$(top_srcdir)/src/common/capwap_element_80211_statistics.c \ $(top_srcdir)/src/common/capwap_element_80211_txpower.c \
$(top_srcdir)/src/common/capwap_element_80211_supportedrates.c \ $(top_srcdir)/src/common/capwap_element_80211_txpowerlevel.c \
$(top_srcdir)/src/common/capwap_element_80211_txpower.c \ $(top_srcdir)/src/common/capwap_element_80211_updatestationqos.c \
$(top_srcdir)/src/common/capwap_element_80211_txpowerlevel.c \ $(top_srcdir)/src/common/capwap_element_80211_updatewlan.c \
$(top_srcdir)/src/common/capwap_element_80211_updatestationqos.c \ $(top_srcdir)/src/common/capwap_element_80211_wtpqos.c \
$(top_srcdir)/src/common/capwap_element_80211_updatewlan.c \ $(top_srcdir)/src/common/capwap_element_80211_wtpradioconf.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpqos.c \ $(top_srcdir)/src/common/capwap_element_80211_wtpradiofailalarm.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpradioconf.c \ $(top_srcdir)/src/common/capwap_element_80211_wtpradioinformation.c
$(top_srcdir)/src/common/capwap_element_80211_wtpradiofailalarm.c \
$(top_srcdir)/src/common/capwap_element_80211_wtpradioinformation.c if DEBUG_BUILD
capwap_SOURCES += $(top_srcdir)/src/common/capwap_debug.c
if DEBUG_BUILD endif
capwap_SOURCES += $(top_srcdir)/src/common/capwap_debug.c
endif

View File

@ -1,96 +1,90 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC # SmartCAPWAP -- An Open Source CAPWAP WTP / AC
# #
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com> # Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING included with this # along with this program (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc., # distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
$(srcdir)/Makefile.in
bin_PROGRAMS = ac
bin_PROGRAMS = ac
AM_CFLAGS = -DCAPWAP_MULTITHREADING_ENABLE \
AM_CFLAGS = \ -D_REENTRANT \
-DCAPWAP_MULTITHREADING_ENABLE \ -D_GNU_SOURCE \
-D_REENTRANT \ ${LIBNL_CFLAGS} \
-D_GNU_SOURCE \ $(LIBXML2_CFLAGS) \
${LIBNL_CFLAGS} \ $(CYASSL_CFLAGS)
$(LIBXML2_CFLAGS) \
$(CYASSL_CFLAGS) AM_CFLAGS += -I$(top_srcdir)/build \
-I$(top_srcdir)/src/common \
INCLUDES = \ -I$(top_srcdir)/src/ac \
-I$(top_srcdir)/build \ -I$(top_srcdir)/src/ac/kmod \
-I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/common/binding/ieee80211
-I$(top_srcdir)/src/ac \
-I$(top_srcdir)/src/ac/kmod \ include $(top_srcdir)/build/Makefile_common.am
-I$(top_srcdir)/src/common/binding/ieee80211
ac_SOURCES = $(capwap_SOURCES) \
include $(top_srcdir)/build/Makefile_common.am $(top_srcdir)/src/common/capwap_event.c \
$(top_srcdir)/src/common/capwap_lock.c \
ac_SOURCES = \ $(top_srcdir)/src/common/capwap_rwlock.c \
$(capwap_SOURCES) \ $(top_srcdir)/src/common/capwap_socket.c \
$(top_srcdir)/src/common/capwap_event.c \ $(top_srcdir)/src/ac/ac.c \
$(top_srcdir)/src/common/capwap_lock.c \ $(top_srcdir)/src/ac/ac_backend.c \
$(top_srcdir)/src/common/capwap_rwlock.c \ $(top_srcdir)/src/ac/ac_execute.c \
$(top_srcdir)/src/common/capwap_socket.c \ $(top_srcdir)/src/ac/ac_session.c \
$(top_srcdir)/src/ac/ac.c \ $(top_srcdir)/src/ac/ac_wlans.c \
$(top_srcdir)/src/ac/ac_backend.c \ $(top_srcdir)/src/ac/ac_kmod.c \
$(top_srcdir)/src/ac/ac_execute.c \ $(top_srcdir)/src/ac/ac_ieee80211_data.c \
$(top_srcdir)/src/ac/ac_session.c \ $(top_srcdir)/src/ac/ac_discovery.c \
$(top_srcdir)/src/ac/ac_session_data.c \ $(top_srcdir)/src/ac/ac_80211_json.c \
$(top_srcdir)/src/ac/ac_wlans.c \ $(top_srcdir)/src/ac/ac_80211_json_addwlan.c \
$(top_srcdir)/src/ac/ac_kmod.c \ $(top_srcdir)/src/ac/ac_80211_json_antenna.c \
$(top_srcdir)/src/ac/ac_ieee80211_data.c \ $(top_srcdir)/src/ac/ac_80211_json_assignbssid.c \
$(top_srcdir)/src/ac/ac_discovery.c \ $(top_srcdir)/src/ac/ac_80211_json_deletewlan.c \
$(top_srcdir)/src/ac/ac_80211_json.c \ $(top_srcdir)/src/ac/ac_80211_json_directsequencecontrol.c \
$(top_srcdir)/src/ac/ac_80211_json_addwlan.c \ $(top_srcdir)/src/ac/ac_80211_json_ie.c \
$(top_srcdir)/src/ac/ac_80211_json_antenna.c \ $(top_srcdir)/src/ac/ac_80211_json_macoperation.c \
$(top_srcdir)/src/ac/ac_80211_json_assignbssid.c \ $(top_srcdir)/src/ac/ac_80211_json_miccountermeasures.c \
$(top_srcdir)/src/ac/ac_80211_json_deletewlan.c \ $(top_srcdir)/src/ac/ac_80211_json_multidomaincapability.c \
$(top_srcdir)/src/ac/ac_80211_json_directsequencecontrol.c \ $(top_srcdir)/src/ac/ac_80211_json_ofdmcontrol.c \
$(top_srcdir)/src/ac/ac_80211_json_ie.c \ $(top_srcdir)/src/ac/ac_80211_json_rateset.c \
$(top_srcdir)/src/ac/ac_80211_json_macoperation.c \ $(top_srcdir)/src/ac/ac_80211_json_rsnaerrorreport.c \
$(top_srcdir)/src/ac/ac_80211_json_miccountermeasures.c \ $(top_srcdir)/src/ac/ac_80211_json_statistics.c \
$(top_srcdir)/src/ac/ac_80211_json_multidomaincapability.c \ $(top_srcdir)/src/ac/ac_80211_json_supportedrates.c \
$(top_srcdir)/src/ac/ac_80211_json_ofdmcontrol.c \ $(top_srcdir)/src/ac/ac_80211_json_txpower.c \
$(top_srcdir)/src/ac/ac_80211_json_rateset.c \ $(top_srcdir)/src/ac/ac_80211_json_txpowerlevel.c \
$(top_srcdir)/src/ac/ac_80211_json_rsnaerrorreport.c \ $(top_srcdir)/src/ac/ac_80211_json_updatewlan.c \
$(top_srcdir)/src/ac/ac_80211_json_statistics.c \ $(top_srcdir)/src/ac/ac_80211_json_wtpqos.c \
$(top_srcdir)/src/ac/ac_80211_json_supportedrates.c \ $(top_srcdir)/src/ac/ac_80211_json_wtpradioconf.c \
$(top_srcdir)/src/ac/ac_80211_json_txpower.c \ $(top_srcdir)/src/ac/ac_80211_json_wtpradiofailalarm.c \
$(top_srcdir)/src/ac/ac_80211_json_txpowerlevel.c \ $(top_srcdir)/src/ac/ac_80211_json_wtpradioinformation.c \
$(top_srcdir)/src/ac/ac_80211_json_updatewlan.c \ $(top_srcdir)/src/ac/ac_dfa_join.c \
$(top_srcdir)/src/ac/ac_80211_json_wtpqos.c \ $(top_srcdir)/src/ac/ac_dfa_configure.c \
$(top_srcdir)/src/ac/ac_80211_json_wtpradioconf.c \ $(top_srcdir)/src/ac/ac_dfa_imagedata.c \
$(top_srcdir)/src/ac/ac_80211_json_wtpradiofailalarm.c \ $(top_srcdir)/src/ac/ac_dfa_datacheck.c \
$(top_srcdir)/src/ac/ac_80211_json_wtpradioinformation.c \ $(top_srcdir)/src/ac/ac_dfa_dtls.c \
$(top_srcdir)/src/ac/ac_dfa_join.c \ $(top_srcdir)/src/ac/ac_dfa_run.c \
$(top_srcdir)/src/ac/ac_dfa_configure.c \ $(top_srcdir)/src/ac/ac_dfa_reset.c \
$(top_srcdir)/src/ac/ac_dfa_imagedata.c \ $(top_srcdir)/src/ac/ac_dfa_teardown.c \
$(top_srcdir)/src/ac/ac_dfa_datacheck.c \ $(top_srcdir)/src/ac/ac_soap.c \
$(top_srcdir)/src/ac/ac_dfa_dtls.c \ $(top_srcdir)/src/common/binding/ieee80211/ieee80211.c
$(top_srcdir)/src/ac/ac_dfa_run.c \
$(top_srcdir)/src/ac/ac_dfa_reset.c \ ac_LDADD = $(CONFIG_LIBS) \
$(top_srcdir)/src/ac/ac_dfa_teardown.c \ $(PTHREAD_LIBS) \
$(top_srcdir)/src/ac/ac_soap.c \ $(LIBXML2_LIBS) \
$(top_srcdir)/src/common/binding/ieee80211/ieee80211.c $(LIBJSON_LIBS) \
$(CYASSL_LIBS) \
ac_LDADD = \ $(LIBNL_LIBS)
$(CONFIG_LIBS) \
$(PTHREAD_LIBS) \
$(LIBXML2_LIBS) \
$(LIBJSON_LIBS) \
$(CYASSL_LIBS) \
$(LIBNL_LIBS)

View File

@ -1,75 +1,70 @@
# SmartCAPWAP -- An Open Source CAPWAP WTP / AC # SmartCAPWAP -- An Open Source CAPWAP WTP / AC
# #
# Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com> # Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING included with this # along with this program (see the file COPYING included with this
# distribution); if not, write to the Free Software Foundation, Inc., # distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
MAINTAINERCLEANFILES = \ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
$(srcdir)/Makefile.in
bin_PROGRAMS = wtp
bin_PROGRAMS = wtp
AM_CFLAGS = -D_REENTRANT \
AM_CFLAGS = \ -D_GNU_SOURCE \
-D_REENTRANT \ ${LIBNL_CFLAGS}
-D_GNU_SOURCE \
${LIBNL_CFLAGS} if DTLS_ENABLED
AM_CFLAGS += $(CYASSL_CFLAGS)
if DTLS_ENABLED endif
AM_CFLAGS += $(CYASSL_CFLAGS)
endif AM_CFLAGS += -I$(top_srcdir)/build \
-I$(top_srcdir)/src/common \
INCLUDES = \ -I$(top_srcdir)/src/wtp \
-I$(top_srcdir)/build \ -I$(top_srcdir)/src/wtp/kmod \
-I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/common/binding/ieee80211 \
-I$(top_srcdir)/src/wtp \ -I$(top_srcdir)/src/wtp/binding/ieee80211
-I$(top_srcdir)/src/wtp/kmod \
-I$(top_srcdir)/src/common/binding/ieee80211 \ include $(top_srcdir)/build/Makefile_common.am
-I$(top_srcdir)/src/wtp/binding/ieee80211
wtp_SOURCES = $(capwap_SOURCES) \
include $(top_srcdir)/build/Makefile_common.am $(top_srcdir)/src/wtp/wtp.c \
$(top_srcdir)/src/wtp/wtp_kmod.c \
wtp_SOURCES = \ $(top_srcdir)/src/wtp/wtp_element_helper.c \
$(capwap_SOURCES) \ $(top_srcdir)/src/wtp/wtp_dfa.c \
$(top_srcdir)/src/wtp/wtp.c \ $(top_srcdir)/src/wtp/wtp_dfa_idle.c \
$(top_srcdir)/src/wtp/wtp_kmod.c \ $(top_srcdir)/src/wtp/wtp_dfa_discovery.c \
$(top_srcdir)/src/wtp/wtp_element_helper.c \ $(top_srcdir)/src/wtp/wtp_dfa_sulking.c \
$(top_srcdir)/src/wtp/wtp_dfa.c \ $(top_srcdir)/src/wtp/wtp_dfa_dtls.c \
$(top_srcdir)/src/wtp/wtp_dfa_idle.c \ $(top_srcdir)/src/wtp/wtp_dfa_join.c \
$(top_srcdir)/src/wtp/wtp_dfa_discovery.c \ $(top_srcdir)/src/wtp/wtp_dfa_configure.c \
$(top_srcdir)/src/wtp/wtp_dfa_sulking.c \ $(top_srcdir)/src/wtp/wtp_dfa_datacheck.c \
$(top_srcdir)/src/wtp/wtp_dfa_dtls.c \ $(top_srcdir)/src/wtp/wtp_dfa_run.c \
$(top_srcdir)/src/wtp/wtp_dfa_join.c \ $(top_srcdir)/src/wtp/wtp_dfa_reset.c \
$(top_srcdir)/src/wtp/wtp_dfa_configure.c \ $(top_srcdir)/src/wtp/wtp_dfa_imagedata.c \
$(top_srcdir)/src/wtp/wtp_dfa_datacheck.c \ $(top_srcdir)/src/wtp/wtp_radio.c \
$(top_srcdir)/src/wtp/wtp_dfa_run.c \ $(top_srcdir)/src/common/binding/ieee80211/ieee80211.c \
$(top_srcdir)/src/wtp/wtp_dfa_reset.c \ $(top_srcdir)/src/wtp/binding/ieee80211/netlink_link.c \
$(top_srcdir)/src/wtp/wtp_dfa_imagedata.c \ $(top_srcdir)/src/wtp/binding/ieee80211/wifi_drivers.c
$(top_srcdir)/src/wtp/wtp_radio.c \
$(top_srcdir)/src/common/binding/ieee80211/ieee80211.c \ wtp_LDADD = $(CONFIG_LIBS) \
$(top_srcdir)/src/wtp/binding/ieee80211/netlink_link.c \ $(LIBNL_LIBS)
$(top_srcdir)/src/wtp/binding/ieee80211/wifi_drivers.c
if DTLS_ENABLED
wtp_LDADD = \ wtp_LDADD += $(CYASSL_LIBS)
$(CONFIG_LIBS) \ endif
$(LIBNL_LIBS)
if BUILD_WTP_WIFI_DRIVERS_NL80211
if DTLS_ENABLED wtp_SOURCES += $(top_srcdir)/src/wtp/binding/ieee80211/wifi_nl80211.c
wtp_LDADD += $(CYASSL_LIBS) endif
endif
if BUILD_WTP_WIFI_DRIVERS_NL80211
wtp_SOURCES += $(top_srcdir)/src/wtp/binding/ieee80211/wifi_nl80211.c
endif

View File

@ -66,12 +66,9 @@ application: {
network: { network: {
#binding = "eth1"; #binding = "eth1";
mtu = 1500; #listen = "";
transport = "udp"; transport = "udp";
mtu = 1500;
ipv4 = true;
ipv6 = false;
ipdualstack = true;
}; };
}; };

View File

@ -12,7 +12,6 @@ application: {
binding = "802.11"; binding = "802.11";
tunnelmode: { tunnelmode: {
dataframe = "usermode";
nativeframe = false; nativeframe = false;
ethframe = false; ethframe = false;
localbridging = true; localbridging = true;
@ -119,13 +118,10 @@ application: {
network: { network: {
#binding = "eth1"; #binding = "eth1";
mtu = 1500; #listen = "";
#port = 0;
transport = "udp"; transport = "udp";
mtu = 1500;
ipv4 = true;
ipv6 = false;
ipdualstack = true;
}; };
acdiscovery: { acdiscovery: {

View File

@ -17,13 +17,12 @@
# distribution); if not, write to the Free Software Foundation, Inc., # distribution); if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AC_PREREQ(2.60) AC_PREREQ(2.63)
m4_include(version.m4) AC_INIT([SmartCAPWAP], [1.0.0], [https://bitbucket.org/vemax78/smartcapwap], [smartcapwap])
AC_INIT([PRODUCT_NAME], [PRODUCT_VERSION], [PRODUCT_BUGREPORT], [PRODUCT_TARNAME]) AC_CONFIG_AUX_DIR([build])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE([1.11 -Wall -Werror])
AC_USE_SYSTEM_EXTENSIONS AC_USE_SYSTEM_EXTENSIONS
# cross-compile macros # cross-compile macros
@ -34,45 +33,50 @@ AC_CANONICAL_HOST
AC_COPYRIGHT("SmartCapwap by Massimo Vellucci <vemax78@gmail.com>") AC_COPYRIGHT("SmartCapwap by Massimo Vellucci <vemax78@gmail.com>")
AC_REVISION($Revision: 1.0 $) AC_REVISION($Revision: 1.0 $)
#
AC_PROG_INSTALL
AC_LANG(C)
AC_HEADER_STDC
# #
AC_ARG_ENABLE( AC_ARG_ENABLE(
[dtls], [dtls],
[AS_HELP_STRING([--disable-dtls], [disable DTLS support @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-dtls], [disable DTLS support])],
, ,
[enable_dtls="yes"] [enable_dtls="yes"]
) )
AC_ARG_ENABLE( AC_ARG_ENABLE(
[debug], [debug],
[AS_HELP_STRING([--disable-debug], [disable debug support @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-debug], [disable debug support])],
, ,
[enable_debug="yes"] [enable_debug="yes"]
) )
AC_ARG_ENABLE( AC_ARG_ENABLE(
[logging], [logging],
[AS_HELP_STRING([--disable-logging], [disable logging support @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-logging], [disable logging support])],
, ,
[enable_logging="yes"] [enable_logging="yes"]
) )
AC_ARG_ENABLE( AC_ARG_ENABLE(
[ac], [ac],
[AS_HELP_STRING([--disable-ac], [disable ac support @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-ac], [disable ac support])],
, ,
[enable_ac="yes"] [enable_ac="yes"]
) )
AC_ARG_ENABLE( AC_ARG_ENABLE(
[wtp], [wtp],
[AS_HELP_STRING([--disable-wtp], [disable wtp support @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-wtp], [disable wtp support])],
, ,
[enable_wtp="yes"] [enable_wtp="yes"]
) )
AC_ARG_WITH( AC_ARG_WITH(
[mem-check], [mem-check],
[AS_HELP_STRING([--with-mem-check=TYPE], [build with debug memory checking, TYPE=no|internal|valgrind @<:@default=internal@:>@])], [AS_HELP_STRING([--with-mem-check=TYPE], [build with debug memory checking, TYPE=no|internal|valgrind])],
[ [
case "${withval}" in case "${withval}" in
valgrind|internal|no) ;; valgrind|internal|no) ;;
@ -85,7 +89,7 @@ AC_ARG_WITH(
# WTP drivers wifi binding # WTP drivers wifi binding
AC_ARG_ENABLE( AC_ARG_ENABLE(
[wifi-drivers-nl80211], [wifi-drivers-nl80211],
[AS_HELP_STRING([--disable-wifi-drivers-nl80211], [disable WTP support for nl80211 wifi binding @<:@default=yes@:>@])], [AS_HELP_STRING([--disable-wifi-drivers-nl80211], [disable WTP support for nl80211 wifi binding])],
, ,
[enable_wifi_drivers_nl80211="yes"] [enable_wifi_drivers_nl80211="yes"]
) )
@ -112,13 +116,6 @@ else
AC_DEFINE([DISABLE_LOGGING_DEBUG], [1], [Disable logging debug]) AC_DEFINE([DISABLE_LOGGING_DEBUG], [1], [Disable logging debug])
fi fi
#
AC_PROG_INSTALL
AC_LANG(C)
AC_HEADER_STDC
# Check LIBCONFIG library # Check LIBCONFIG library
AC_CHECK_HEADER([libconfig.h], [], [AC_MSG_ERROR(You need the libconfig headers)]) 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)]) AC_CHECK_LIB([config], [config_init], [CONFIG_LIBS="-lconfig"], [AC_MSG_ERROR(You need the libconfig library)])

View File

@ -40,7 +40,7 @@ define KernelPackage/smartcapwap
SUBMENU:=Network Support SUBMENU:=Network Support
TITLE:=SmartCAPWAP Data Channel Module TITLE:=SmartCAPWAP Data Channel Module
MAINTAINER:=Massimo Vellucci <vemax78@gmail.com> MAINTAINER:=Massimo Vellucci <vemax78@gmail.com>
DEPENDS:=+kmod-mac80211 DEPENDS:=+kmod-mac80211 +kmod-ipv6
FILES:=$(PKG_BUILD_DIR)/src/wtp/kmod/smartcapwap.ko FILES:=$(PKG_BUILD_DIR)/src/wtp/kmod/smartcapwap.ko
AUTOLOAD:=$(call AutoLoad,70,smartcapwap) AUTOLOAD:=$(call AutoLoad,70,smartcapwap)
endef endef
@ -74,7 +74,7 @@ define Build/Compile/kmod
SUBDIRS="$(PKG_BUILD_DIR)/src/wtp/kmod" \ SUBDIRS="$(PKG_BUILD_DIR)/src/wtp/kmod" \
KLIB_BUILD="$(LINUX_DIR)" \ KLIB_BUILD="$(LINUX_DIR)" \
KLIB="$(TARGET_MODULES_DIR)" \ KLIB="$(TARGET_MODULES_DIR)" \
KBUILD_EXTRA_SYMBOLS="$(LINUX_DIR)/../compat-wireless-2014-03-31/Module.symvers" \ KBUILD_EXTRA_SYMBOLS="$(LINUX_DIR)/../compat-wireless-2014-05-22/Module.symvers" \
LINUXINCLUDE="-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \ LINUXINCLUDE="-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
-I$(STAGING_DIR)/usr/include/mac80211-backport \ -I$(STAGING_DIR)/usr/include/mac80211-backport \
-I$(STAGING_DIR)/usr/include/mac80211/uapi \ -I$(STAGING_DIR)/usr/include/mac80211/uapi \

View File

@ -1,6 +1,6 @@
--- a/include/net/mac80211.h 2014-06-02 11:48:37.000000000 +0200 --- a/include/net/mac80211.h 2014-07-10 19:19:55.000000000 +0200
+++ b/include/net/mac80211.h 2014-06-07 17:23:03.000000000 +0200 +++ b/include/net/mac80211.h 2014-07-10 20:52:02.000000000 +0200
@@ -4699,4 +4699,24 @@ int ieee80211_parse_p2p_noa(const struct @@ -4772,4 +4772,24 @@ int ieee80211_parse_p2p_noa(const struct
*/ */
void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf); void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
@ -17,16 +17,16 @@
+/** +/**
+ * + *
+ */ + */
+int ieee80211_pcktunnel_register(u32 ifindex, struct ieee80211_pcktunnel *handler); +int ieee80211_pcktunnel_register(struct net_device *dev, struct ieee80211_pcktunnel *handler);
+ +
+/** +/**
+ * + *
+ */ + */
+int ieee80211_pcktunnel_deregister(u32 ifindex, struct ieee80211_pcktunnel *handler); +int ieee80211_pcktunnel_deregister(struct net_device *dev, struct ieee80211_pcktunnel *handler);
+ +
#endif /* MAC80211_H */ #endif /* MAC80211_H */
--- a/net/mac80211/ieee80211_i.h 2014-06-02 11:48:37.000000000 +0200 --- a/net/mac80211/ieee80211_i.h 2014-07-10 19:19:55.000000000 +0200
+++ b/net/mac80211/ieee80211_i.h 2014-06-07 17:14:25.000000000 +0200 +++ b/net/mac80211/ieee80211_i.h 2014-07-10 20:47:56.000000000 +0200
@@ -165,6 +165,7 @@ typedef unsigned __bitwise__ ieee80211_r @@ -165,6 +165,7 @@ typedef unsigned __bitwise__ ieee80211_r
#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u)
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
@ -35,7 +35,7 @@
/** /**
* enum ieee80211_packet_rx_flags - packet RX flags * enum ieee80211_packet_rx_flags - packet RX flags
@@ -727,6 +728,9 @@ struct ieee80211_sub_if_data { @@ -743,6 +744,9 @@ struct ieee80211_sub_if_data {
char name[IFNAMSIZ]; char name[IFNAMSIZ];
@ -45,34 +45,17 @@
/* Fragment table for host-based reassembly */ /* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next; unsigned int fragment_next;
--- a/net/mac80211/iface.c 2014-06-02 11:48:37.000000000 +0200 --- a/net/mac80211/iface.c 2014-07-10 19:19:55.000000000 +0200
+++ b/net/mac80211/iface.c 2014-06-04 22:52:06.000000000 +0200 +++ b/net/mac80211/iface.c 2014-07-10 20:51:28.000000000 +0200
@@ -1850,3 +1850,80 @@ void ieee80211_iface_exit(void) @@ -1844,3 +1844,45 @@ void ieee80211_iface_exit(void)
{ {
unregister_netdevice_notifier(&mac80211_netdev_notifier); unregister_netdevice_notifier(&mac80211_netdev_notifier);
} }
+ +
+ +int ieee80211_pcktunnel_register(struct net_device *dev, struct ieee80211_pcktunnel *handler)
+int ieee80211_pcktunnel_register(u32 ifindex, struct ieee80211_pcktunnel *handler)
+{ +{
+ int ret = 0; + int ret = 0;
+ struct net_device *dev; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata;
+
+ /* Retrieve device from ifindex */
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (!dev) {
+ return -ENODEV;
+ }
+
+ /* Check if wireless device */
+ if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
+ dev_put(dev);
+ return -EINVAL;
+ }
+
+ /* Add handler to list */
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ +
+ mutex_lock(&sdata->local->iflist_mtx); + mutex_lock(&sdata->local->iflist_mtx);
+ +
@ -85,33 +68,16 @@
+ mutex_unlock(&sdata->local->iflist_mtx); + mutex_unlock(&sdata->local->iflist_mtx);
+ synchronize_net(); + synchronize_net();
+ +
+ dev_put(dev);
+ return ret; + return ret;
+} +}
+EXPORT_SYMBOL(ieee80211_pcktunnel_register); +EXPORT_SYMBOL(ieee80211_pcktunnel_register);
+ +
+int ieee80211_pcktunnel_deregister(u32 ifindex, struct ieee80211_pcktunnel *handler) +int ieee80211_pcktunnel_deregister(struct net_device *dev, struct ieee80211_pcktunnel *handler)
+{ +{
+ int ret = -ENODEV; + int ret = -ENODEV;
+ struct net_device *dev; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_pcktunnel *h; + struct ieee80211_pcktunnel *h;
+ +
+ /* Retrieve device from ifindex */
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (!dev) {
+ return -ENODEV;
+ }
+
+ /* Check if wireless device */
+ if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
+ dev_put(dev);
+ return -EINVAL;
+ }
+
+ /* Remove handler from list */
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx); + mutex_lock(&sdata->local->iflist_mtx);
+ +
+ h = rcu_dereference_protected(sdata->pcktunnel_handlers, lockdep_is_held(&sdata->local->iflist_mtx)); + h = rcu_dereference_protected(sdata->pcktunnel_handlers, lockdep_is_held(&sdata->local->iflist_mtx));
@ -123,14 +89,13 @@
+ mutex_unlock(&sdata->local->iflist_mtx); + mutex_unlock(&sdata->local->iflist_mtx);
+ synchronize_net(); + synchronize_net();
+ +
+ dev_put(dev);
+ return ret; + return ret;
+} +}
+EXPORT_SYMBOL(ieee80211_pcktunnel_deregister); +EXPORT_SYMBOL(ieee80211_pcktunnel_deregister);
+ +
--- a/net/mac80211/rx.c 2014-06-02 11:48:37.000000000 +0200 --- a/net/mac80211/rx.c 2014-07-10 19:19:55.000000000 +0200
+++ b/net/mac80211/rx.c 2014-06-07 17:22:05.000000000 +0200 +++ b/net/mac80211/rx.c 2014-07-10 21:01:19.000000000 +0200
@@ -2828,6 +2828,51 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_ @@ -2831,6 +2831,51 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
return RX_QUEUED; return RX_QUEUED;
} }
@ -182,7 +147,7 @@
/* TODO: use IEEE80211_RX_FRAGMENTED */ /* TODO: use IEEE80211_RX_FRAGMENTED */
static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct ieee80211_rate *rate) struct ieee80211_rate *rate)
@@ -2907,6 +2952,7 @@ static void ieee80211_rx_handlers_result @@ -2910,6 +2955,7 @@ static void ieee80211_rx_handlers_result
if (rx->sta) if (rx->sta)
rx->sta->rx_dropped++; rx->sta->rx_dropped++;
/* fall through */ /* fall through */
@ -190,17 +155,18 @@
case RX_CONTINUE: { case RX_CONTINUE: {
struct ieee80211_rate *rate = NULL; struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
@@ -2935,7 +2981,8 @@ static void ieee80211_rx_handlers_result @@ -2938,7 +2984,9 @@ static void ieee80211_rx_handlers_result
} }
static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
- struct sk_buff_head *frames) - struct sk_buff_head *frames)
+ struct sk_buff_head *frames, + struct sk_buff_head *frames,
+ struct ieee80211_rate *rate) + struct ieee80211_rate *rate)
+
{ {
ieee80211_rx_result res = RX_DROP_MONITOR; ieee80211_rx_result res = RX_DROP_MONITOR;
struct sk_buff *skb; struct sk_buff *skb;
@@ -2968,6 +3015,11 @@ static void ieee80211_rx_handlers(struct @@ -2971,6 +3019,11 @@ static void ieee80211_rx_handlers(struct
if (ieee80211_vif_is_mesh(&rx->sdata->vif)) if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding); CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif #endif
@ -212,7 +178,7 @@
CALL_RXH(ieee80211_rx_h_amsdu) CALL_RXH(ieee80211_rx_h_amsdu)
CALL_RXH(ieee80211_rx_h_data) CALL_RXH(ieee80211_rx_h_data)
@@ -2991,7 +3043,8 @@ static void ieee80211_rx_handlers(struct @@ -2994,7 +3047,8 @@ static void ieee80211_rx_handlers(struct
spin_unlock_bh(&rx->local->rx_path_lock); spin_unlock_bh(&rx->local->rx_path_lock);
} }
@ -222,7 +188,7 @@
{ {
struct sk_buff_head reorder_release; struct sk_buff_head reorder_release;
ieee80211_rx_result res = RX_DROP_MONITOR; ieee80211_rx_result res = RX_DROP_MONITOR;
@@ -3009,7 +3062,7 @@ static void ieee80211_invoke_rx_handlers @@ -3012,7 +3066,7 @@ static void ieee80211_invoke_rx_handlers
ieee80211_rx_reorder_ampdu(rx, &reorder_release); ieee80211_rx_reorder_ampdu(rx, &reorder_release);
@ -231,7 +197,7 @@
return; return;
rxh_next: rxh_next:
@@ -3046,7 +3099,7 @@ void ieee80211_release_reorder_timeout(s @@ -3049,7 +3103,7 @@ void ieee80211_release_reorder_timeout(s
ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames); ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
spin_unlock(&tid_agg_rx->reorder_lock); spin_unlock(&tid_agg_rx->reorder_lock);
@ -240,7 +206,7 @@
} }
/* main receive path */ /* main receive path */
@@ -3160,7 +3213,9 @@ static bool prepare_for_handlers(struct @@ -3163,7 +3217,9 @@ static bool prepare_for_handlers(struct
* or not the skb was consumed. * or not the skb was consumed.
*/ */
static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
@ -251,7 +217,7 @@
{ {
struct ieee80211_local *local = rx->local; struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_sub_if_data *sdata = rx->sdata;
@@ -3186,7 +3241,7 @@ static bool ieee80211_prepare_and_rx_han @@ -3189,7 +3245,7 @@ static bool ieee80211_prepare_and_rx_han
rx->skb = skb; rx->skb = skb;
} }
@ -260,7 +226,7 @@
return true; return true;
} }
@@ -3195,7 +3250,8 @@ static bool ieee80211_prepare_and_rx_han @@ -3198,7 +3254,8 @@ static bool ieee80211_prepare_and_rx_han
* be called with rcu_read_lock protection. * be called with rcu_read_lock protection.
*/ */
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
@ -270,7 +236,7 @@
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
@@ -3248,7 +3304,7 @@ static void __ieee80211_rx_handle_packet @@ -3251,7 +3308,7 @@ static void __ieee80211_rx_handle_packet
rx.sta = prev_sta; rx.sta = prev_sta;
rx.sdata = prev_sta->sdata; rx.sdata = prev_sta->sdata;
@ -279,7 +245,7 @@
prev_sta = sta; prev_sta = sta;
} }
@@ -3257,7 +3313,7 @@ static void __ieee80211_rx_handle_packet @@ -3260,7 +3317,7 @@ static void __ieee80211_rx_handle_packet
rx.sta = prev_sta; rx.sta = prev_sta;
rx.sdata = prev_sta->sdata; rx.sdata = prev_sta->sdata;
@ -288,7 +254,7 @@
return; return;
goto out; goto out;
} }
@@ -3286,7 +3342,7 @@ static void __ieee80211_rx_handle_packet @@ -3289,7 +3346,7 @@ static void __ieee80211_rx_handle_packet
rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev; rx.sdata = prev;
@ -297,7 +263,7 @@
prev = sdata; prev = sdata;
} }
@@ -3295,7 +3351,7 @@ static void __ieee80211_rx_handle_packet @@ -3298,7 +3355,7 @@ static void __ieee80211_rx_handle_packet
rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev; rx.sdata = prev;
@ -306,7 +272,7 @@
return; return;
} }
@@ -3406,7 +3462,7 @@ void ieee80211_rx(struct ieee80211_hw *h @@ -3409,7 +3466,7 @@ void ieee80211_rx(struct ieee80211_hw *h
ieee80211_tpt_led_trig_rx(local, ieee80211_tpt_led_trig_rx(local,
((struct ieee80211_hdr *)skb->data)->frame_control, ((struct ieee80211_hdr *)skb->data)->frame_control,
skb->len); skb->len);

View File

@ -37,9 +37,13 @@ static int ac_init(void) {
/* Network */ /* Network */
capwap_network_init(&g_ac.net); capwap_network_init(&g_ac.net);
g_ac.addrlist = capwap_list_create();
g_ac.mtu = CAPWAP_MTU_DEFAULT; g_ac.mtu = CAPWAP_MTU_DEFAULT;
g_ac.binding = capwap_array_create(sizeof(uint16_t), 0, 0); g_ac.binding = capwap_array_create(sizeof(uint16_t), 0, 0);
g_ac.net.bind_sock_ctrl_port = CAPWAP_CONTROL_PORT;
/* Try to use IPv6 */
g_ac.net.localaddr.ss.ss_family = AF_INET6;
CAPWAP_SET_NETWORK_PORT(&g_ac.net.localaddr, CAPWAP_CONTROL_PORT);
/* Standard name */ /* Standard name */
g_ac.acname.name = (uint8_t*)capwap_duplicate_string(AC_STANDARD_NAME); g_ac.acname.name = (uint8_t*)capwap_duplicate_string(AC_STANDARD_NAME);
@ -134,6 +138,7 @@ static void ac_destroy(void) {
} }
capwap_array_free(g_ac.availablebackends); capwap_array_free(g_ac.availablebackends);
capwap_list_free(g_ac.addrlist);
} }
/* Help */ /* Help */
@ -144,8 +149,6 @@ static void ac_print_usage(void) {
static int ac_parsing_configuration_1_0(config_t* config) { static int ac_parsing_configuration_1_0(config_t* config) {
int i; int i;
int configBool; int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt; LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString; const char* configString;
config_setting_t* configSetting; config_setting_t* configSetting;
@ -519,7 +522,7 @@ static int ac_parsing_configuration_1_0(config_t* config) {
return 0; return 0;
} }
strcpy(g_ac.net.bind_interface, configString); strcpy(g_ac.net.bindiface, configString);
} }
/* Set mtu of AC */ /* Set mtu of AC */
@ -532,16 +535,6 @@ static int ac_parsing_configuration_1_0(config_t* config) {
} }
} }
/* Set network port of WTP */
if (config_lookup_int(config, "application.network.port", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65535)) {
g_ac.net.bind_sock_ctrl_port = (unsigned short)configInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.network.port value");
return 0;
}
}
/* Set transport of AC */ /* Set transport of AC */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) { if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) { if (!strcmp(configString, "udp")) {
@ -554,35 +547,6 @@ static int ac_parsing_configuration_1_0(config_t* config) {
} }
} }
/* 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", &configBool) == CONFIG_TRUE) {
if (!configBool) {
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;
}
}
/* Backend */ /* Backend */
if (config_lookup_string(config, "backend.id", &configString) == CONFIG_TRUE) { if (config_lookup_string(config, "backend.id", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) { if (strlen(configString) > 0) {
@ -754,12 +718,15 @@ static int ac_load_configuration(int argc, char** argv) {
/* Init AC */ /* Init AC */
static int ac_configure(void) { static int ac_configure(void) {
/* Bind to any address */ /* Bind control channel to any address */
if (!capwap_bind_sockets(&g_ac.net)) { if (capwap_bind_sockets(&g_ac.net)) {
capwap_logging_fatal("Cannot bind address"); capwap_logging_fatal("Cannot bind address");
return AC_ERROR_NETWORK; return AC_ERROR_NETWORK;
} }
/* Detect local address */
capwap_interface_list(&g_ac.net, g_ac.addrlist);
return CAPWAP_SUCCESSFUL; return CAPWAP_SUCCESSFUL;
} }
@ -834,24 +801,27 @@ int main(int argc, char** argv) {
result = ac_configure(); result = ac_configure();
if (result == CAPWAP_SUCCESSFUL) { if (result == CAPWAP_SUCCESSFUL) {
/* Connect AC to kernel module */ /* Connect AC to kernel module */
value = ac_kmod_init(); if (!ac_kmod_init(16, 4)) {
if (!value || !g_ac.kmodrequest) { /* Bind data channel */
if (ac_kmod_isconnected()) { if (!ac_kmod_createdatachannel(g_ac.net.localaddr.ss.ss_family, CAPWAP_GET_NETWORK_PORT(&g_ac.net.localaddr) + 1)) {
capwap_logging_info("SmartCAPWAP kernel module connected"); capwap_logging_info("SmartCAPWAP kernel module connected");
/* Running AC */
result = ac_execute();
} else {
capwap_logging_fatal("Unable to create kernel data channel");
} }
/* Running AC */
result = ac_execute();
/* Close connection */
ac_close();
/* Disconnect kernel module */ /* Disconnect kernel module */
ac_kmod_free(); ac_kmod_free();
} else { } else {
capwap_logging_fatal("Unable to connect to kernel module"); capwap_logging_fatal("Unable to connect to kernel module");
} }
/* Close connection */
ac_close();
} }
} }
/* Free memory */ /* Free memory */

View File

@ -61,6 +61,13 @@
#define AC_STATIONS_HASH_SIZE 65536 #define AC_STATIONS_HASH_SIZE 65536
#define AC_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH #define AC_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH
/* */
#define compat_json_object_object_get(obj, key) ({ \
json_bool error; struct json_object* result = NULL; \
error = json_object_object_get_ex(obj, key, &result); \
(error ? result : NULL); \
})
/* */ /* */
struct ac_state { struct ac_state {
struct capwap_ecnsupport_element ecn; struct capwap_ecnsupport_element ecn;
@ -98,10 +105,9 @@ struct ac_t {
/* */ /* */
struct ac_state dfa; struct ac_state dfa;
struct capwap_network net; struct capwap_network net;
struct capwap_list* addrlist;
unsigned short mtu; unsigned short mtu;
struct ac_fds fds;
struct capwap_array* binding; struct capwap_array* binding;
struct capwap_acname_element acname; struct capwap_acname_element acname;
@ -111,7 +117,6 @@ struct ac_t {
int fdmsgsessions[2]; int fdmsgsessions[2];
/* */ /* */
int kmodrequest;
struct ac_kmod_handle kmodhandle; struct ac_kmod_handle kmodhandle;
/* Sessions */ /* Sessions */

View File

@ -229,7 +229,7 @@ int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, s
struct json_object* jsonradio = json_object_array_get_idx(jsonroot, i); struct json_object* jsonradio = json_object_array_get_idx(jsonroot, i);
/* Get RadioID */ /* Get RadioID */
jsonitem = json_object_object_get(jsonradio, "RadioID"); jsonitem = compat_json_object_object_get(jsonradio, "RadioID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int radioid = json_object_get_int(jsonitem); int radioid = json_object_get_int(jsonitem);
if (IS_VALID_RADIOID(radioid)) { if (IS_VALID_RADIOID(radioid)) {

View File

@ -21,7 +21,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
antenna->radioid = radioid; antenna->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "Diversity"); jsonitem = compat_json_object_object_get(jsonparent, "Diversity");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_boolean)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_boolean)) {
antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE); antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE);
} else { } else {
@ -29,7 +29,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "Combiner"); jsonitem = compat_json_object_object_get(jsonparent, "Combiner");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
antenna->combiner = (uint8_t)json_object_get_int(jsonitem); antenna->combiner = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -37,7 +37,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "AntennaSelection"); jsonitem = compat_json_object_object_get(jsonparent, "AntennaSelection");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_array)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_array)) {
int i; int i;
int length; int length;

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
directsequencecontrol->radioid = radioid; directsequencecontrol->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "CurrentChan"); jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -27,7 +27,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "CurrentCCA"); jsonitem = compat_json_object_object_get(jsonparent, "CurrentCCA");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem); directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -35,7 +35,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "EnergyDetectThreshold"); jsonitem = compat_json_object_object_get(jsonparent, "EnergyDetectThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem); directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
macoperation->radioid = radioid; macoperation->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "RTSThreshold"); jsonitem = compat_json_object_object_get(jsonparent, "RTSThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem); macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem);
} else { } else {
@ -30,7 +30,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "ShortRetry"); jsonitem = compat_json_object_object_get(jsonparent, "ShortRetry");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem); macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -38,7 +38,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "LongRetry"); jsonitem = compat_json_object_object_get(jsonparent, "LongRetry");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->longretry = (uint8_t)json_object_get_int(jsonitem); macoperation->longretry = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -46,7 +46,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "FragmentationThreshold"); jsonitem = compat_json_object_object_get(jsonparent, "FragmentationThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem); macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem);
} else { } else {
@ -54,7 +54,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "TxMSDULifetime"); jsonitem = compat_json_object_object_get(jsonparent, "TxMSDULifetime");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem); macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else { } else {
@ -62,7 +62,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "RxMSDULifetime"); jsonitem = compat_json_object_object_get(jsonparent, "RxMSDULifetime");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem); macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
multidomaincapability->radioid = radioid; multidomaincapability->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "FirstChannel"); jsonitem = compat_json_object_object_get(jsonparent, "FirstChannel");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem); multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem);
} else { } else {
@ -27,7 +27,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "NumberChannels"); jsonitem = compat_json_object_object_get(jsonparent, "NumberChannels");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem); multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem);
} else { } else {
@ -35,7 +35,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "MaxTxPowerLevel"); jsonitem = compat_json_object_object_get(jsonparent, "MaxTxPowerLevel");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem); multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
ofdmcontrol->radioid = radioid; ofdmcontrol->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "CurrentChan"); jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -27,7 +27,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "BandSupport"); jsonitem = compat_json_object_object_get(jsonparent, "BandSupport");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK; ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK;
} else { } else {
@ -35,7 +35,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "TIThreshold"); jsonitem = compat_json_object_object_get(jsonparent, "TIThreshold");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem); ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_txpower_createmessageelement(struct json_object* json
txpower->radioid = radioid; txpower->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "CurrentTxPower"); jsonitem = compat_json_object_object_get(jsonparent, "CurrentTxPower");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem); txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
wtpradioconf->radioid = radioid; wtpradioconf->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "ShortPreamble"); jsonitem = compat_json_object_object_get(jsonparent, "ShortPreamble");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem); wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -30,7 +30,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "NumBSSIDs"); jsonitem = compat_json_object_object_get(jsonparent, "NumBSSIDs");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem); wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -38,7 +38,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "DTIMPeriod"); jsonitem = compat_json_object_object_get(jsonparent, "DTIMPeriod");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem); wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -46,7 +46,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "BSSID"); jsonitem = compat_json_object_object_get(jsonparent, "BSSID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
if (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) { if (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) {
capwap_free(wtpradioconf); capwap_free(wtpradioconf);
@ -57,7 +57,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "BeaconPeriod"); jsonitem = compat_json_object_object_get(jsonparent, "BeaconPeriod");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem); wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem);
} else { } else {
@ -65,7 +65,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
return NULL; return NULL;
} }
jsonitem = json_object_object_get(jsonparent, "CountryString"); jsonitem = compat_json_object_object_get(jsonparent, "CountryString");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* country = json_object_get_string(jsonitem); const char* country = json_object_get_string(jsonitem);
if (strlen(country) == (CAPWAP_WTP_RADIO_CONF_COUNTRY_LENGTH - 1)) { if (strlen(country) == (CAPWAP_WTP_RADIO_CONF_COUNTRY_LENGTH - 1)) {

View File

@ -18,7 +18,7 @@ static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_ob
wtpradiofailalarm->radioid = radioid; wtpradiofailalarm->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "Type"); jsonitem = compat_json_object_object_get(jsonparent, "Type");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem); wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem);
} else { } else {
@ -27,7 +27,7 @@ static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_ob
} }
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "Status"); jsonitem = compat_json_object_object_get(jsonparent, "Status");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem); wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem);
} else { } else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_wtpradioinformation_createmessageelement(struct json_
wtpradioinformation->radioid = radioid; wtpradioinformation->radioid = radioid;
/* */ /* */
jsonitem = json_object_object_get(jsonparent, "Mode"); jsonitem = compat_json_object_object_get(jsonparent, "Mode");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK; wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK;
} else { } else {

View File

@ -45,7 +45,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct
*/ */
/* WTPId */ /* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId"); jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0; return 0;
} }
@ -93,19 +93,19 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob
*/ */
/* WTPId */ /* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId"); jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0; return 0;
} }
/* ImageIdentifier */ /* ImageIdentifier */
jsonimage = json_object_object_get(jsonparams, "ImageIdentifier"); jsonimage = compat_json_object_object_get(jsonparams, "ImageIdentifier");
if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) { if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) {
return 0; return 0;
} }
jsonvendor = json_object_object_get(jsonimage, "Vendor"); jsonvendor = compat_json_object_object_get(jsonimage, "Vendor");
jsondata = json_object_object_get(jsonimage, "Data"); jsondata = compat_json_object_object_get(jsonimage, "Data");
if (!jsonvendor || !jsondata || (json_object_get_type(jsonvendor) != json_type_int) || (json_object_get_type(jsondata) != json_type_string)) { if (!jsonvendor || !jsondata || (json_object_get_type(jsonvendor) != json_type_int) || (json_object_get_type(jsondata) != json_type_string)) {
return 0; return 0;
} }
@ -186,25 +186,25 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
*/ */
/* WTPId */ /* WTPId */
jsonwtpid = json_object_object_get(jsonparams, "WTPId"); jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId");
if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) {
return 0; return 0;
} }
/* RadioId */ /* RadioId */
jsonradioid = json_object_object_get(jsonparams, "RadioId"); jsonradioid = compat_json_object_object_get(jsonparams, "RadioId");
if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) { if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) {
return 0; return 0;
} }
/* VirtualAPId */ /* VirtualAPId */
jsonwlanid = json_object_object_get(jsonparams, "VirtualAPId"); jsonwlanid = compat_json_object_object_get(jsonparams, "VirtualAPId");
if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) { if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) {
return 0; return 0;
} }
/* Capability */ /* Capability */
jsoncapability = json_object_object_get(jsonparams, "Capability"); jsoncapability = compat_json_object_object_get(jsonparams, "Capability");
if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) { if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) {
return 0; return 0;
} }
@ -213,37 +213,37 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
/* TODO */ /* TODO */
/* DefaultQoS */ /* DefaultQoS */
jsonqos = json_object_object_get(jsonparams, "DefaultQoS"); jsonqos = compat_json_object_object_get(jsonparams, "DefaultQoS");
if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) { if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) {
return 0; return 0;
} }
/* AuthType */ /* AuthType */
jsonauthtype = json_object_object_get(jsonparams, "AuthType"); jsonauthtype = compat_json_object_object_get(jsonparams, "AuthType");
if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) { if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) {
return 0; return 0;
} }
/* MACMode */ /* MACMode */
jsonmacmode = json_object_object_get(jsonparams, "MACMode"); jsonmacmode = compat_json_object_object_get(jsonparams, "MACMode");
if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) { if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) {
return 0; return 0;
} }
/* TunnelMode */ /* TunnelMode */
jsontunnelmode = json_object_object_get(jsonparams, "TunnelMode"); jsontunnelmode = compat_json_object_object_get(jsonparams, "TunnelMode");
if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) { if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) {
return 0; return 0;
} }
/* SuppressSSID */ /* SuppressSSID */
jsonhidessid = json_object_object_get(jsonparams, "SuppressSSID"); jsonhidessid = compat_json_object_object_get(jsonparams, "SuppressSSID");
if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) { if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) {
return 0; return 0;
} }
/* SSID */ /* SSID */
jsonssid = json_object_object_get(jsonparams, "SSID"); jsonssid = compat_json_object_object_get(jsonparams, "SSID");
if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) { if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) {
ssid = json_object_get_string(jsonssid); ssid = json_object_get_string(jsonssid);
if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) { if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) {
@ -386,16 +386,16 @@ static void ac_backend_parsing_event(struct json_object* jsonitem) {
*/ */
/* Get EventID */ /* Get EventID */
jsonvalue = json_object_object_get(jsonitem, "EventID"); jsonvalue = compat_json_object_object_get(jsonitem, "EventID");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) {
const char* idevent = json_object_get_string(jsonvalue); const char* idevent = json_object_get_string(jsonvalue);
/* Get Action */ /* Get Action */
jsonvalue = json_object_object_get(jsonitem, "Action"); jsonvalue = compat_json_object_object_get(jsonitem, "Action");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) {
const char* action = json_object_get_string(jsonvalue); const char* action = json_object_get_string(jsonvalue);
if (action) { if (action) {
jsonvalue = json_object_object_get(jsonitem, "Params"); jsonvalue = compat_json_object_object_get(jsonitem, "Params");
if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) {
int result = 0; int result = 0;

View File

@ -424,12 +424,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* CAPWAP Timers */ /* CAPWAP Timers */
memcpy(&responsetimers, &session->dfa.timers, sizeof(struct capwap_timers_element)); memcpy(&responsetimers, &session->dfa.timers, sizeof(struct capwap_timers_element));
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "CAPWAPTimers"); jsonelement = compat_json_object_object_get(jsonroot, "CAPWAPTimers");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem; struct json_object* jsonitem;
/* Discovery */ /* Discovery */
jsonitem = json_object_object_get(jsonelement, "Discovery"); jsonitem = compat_json_object_object_get(jsonelement, "Discovery");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) { if ((value > 0) && (value < 256)) {
@ -438,7 +438,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
} }
/* EchoRequest */ /* EchoRequest */
jsonitem = json_object_object_get(jsonelement, "EchoRequest"); jsonitem = compat_json_object_object_get(jsonelement, "EchoRequest");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) { if ((value > 0) && (value < 256)) {
@ -453,7 +453,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* Decryption Error Report Period */ /* Decryption Error Report Period */
jsonelement = NULL; jsonelement = NULL;
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "DecryptionErrorReportPeriod"); jsonelement = compat_json_object_object_get(jsonroot, "DecryptionErrorReportPeriod");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement); length = json_object_array_length(jsonelement);
} else { } else {
@ -480,12 +480,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem; struct json_object* jsonitem;
/* RadioID */ /* RadioID */
jsonitem = json_object_object_get(jsonvalue, "RadioID"); jsonitem = compat_json_object_object_get(jsonvalue, "RadioID");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256) && ((uint8_t)value == report.radioid)) { if ((value > 0) && (value < 256) && ((uint8_t)value == report.radioid)) {
/* Get ReportInterval value */ /* Get ReportInterval value */
jsonitem = json_object_object_get(jsonvalue, "ReportInterval"); jsonitem = compat_json_object_object_get(jsonvalue, "ReportInterval");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
value = json_object_get_int(jsonitem); value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 65536)) { if ((value > 0) && (value < 65536)) {
@ -506,12 +506,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* IdleTimeout */ /* IdleTimeout */
memcpy(&responseidletimeout, &session->dfa.idletimeout, sizeof(struct capwap_idletimeout_element)); memcpy(&responseidletimeout, &session->dfa.idletimeout, sizeof(struct capwap_idletimeout_element));
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "IdleTimeout"); jsonelement = compat_json_object_object_get(jsonroot, "IdleTimeout");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem; struct json_object* jsonitem;
/* Timeout */ /* Timeout */
jsonitem = json_object_object_get(jsonelement, "Timeout"); jsonitem = compat_json_object_object_get(jsonelement, "Timeout");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
if (value > 0) { if (value > 0) {
@ -526,12 +526,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* WTPFallback */ /* WTPFallback */
memcpy(&responsewtpfallback, &session->dfa.wtpfallback, sizeof(struct capwap_wtpfallback_element)); memcpy(&responsewtpfallback, &session->dfa.wtpfallback, sizeof(struct capwap_wtpfallback_element));
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "WTPFallback"); jsonelement = compat_json_object_object_get(jsonroot, "WTPFallback");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem; struct json_object* jsonitem;
/* Mode */ /* Mode */
jsonitem = json_object_object_get(jsonelement, "Mode"); jsonitem = compat_json_object_object_get(jsonelement, "Mode");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) { if ((value > 0) && (value < 256)) {
@ -546,7 +546,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* ACIPv4List */ /* ACIPv4List */
jsonelement = NULL; jsonelement = NULL;
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv4List"); jsonelement = compat_json_object_object_get(jsonroot, "ACIPv4List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement); length = json_object_array_length(jsonelement);
} else { } else {
@ -567,17 +567,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem; struct json_object* jsonitem;
/* ACIPAddress */ /* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress"); jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem); const char* value = json_object_get_string(jsonitem);
if (value) { if (value) {
struct sockaddr_storage address; union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) { if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */ /* Accept only IPv4 address */
if (address.ss_family == AF_INET) { if (address.ss.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count); struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count);
memcpy(responseaddress_in, &address_in->sin_addr, sizeof(struct in_addr)); memcpy(responseaddress_in, &address.sin.sin_addr, sizeof(struct in_addr));
} }
} }
} }
@ -598,7 +597,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* ACIPv6List */ /* ACIPv6List */
jsonelement = NULL; jsonelement = NULL;
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv6List"); jsonelement = compat_json_object_object_get(jsonroot, "ACIPv6List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement); length = json_object_array_length(jsonelement);
} else { } else {
@ -619,17 +618,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem; struct json_object* jsonitem;
/* ACIPAddress */ /* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress"); jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem); const char* value = json_object_get_string(jsonitem);
if (value) { if (value) {
struct sockaddr_storage address; union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) { if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */ /* Accept only IPv6 address */
if (address.ss_family == AF_INET6) { if (address.ss.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count); struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count);
memcpy(responseaddress_in6, &address_in6->sin6_addr, sizeof(struct in6_addr)); memcpy(responseaddress_in6, &address.sin6.sin6_addr, sizeof(struct in6_addr));
} }
} }
} }
@ -649,43 +647,43 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* WTPStaticIPAddressInformation */ /* WTPStaticIPAddressInformation */
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "WTPStaticIPAddressInformation"); jsonelement = compat_json_object_object_get(jsonroot, "WTPStaticIPAddressInformation");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_object)) {
struct json_object* jsonitem; struct json_object* jsonitem;
/* IPAddress */ /* IPAddress */
jsonitem = json_object_object_get(jsonelement, "IPAddress"); jsonitem = compat_json_object_object_get(jsonelement, "IPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage address; union sockaddr_capwap address;
const char* addressvalue = json_object_get_string(jsonitem); const char* addressvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(addressvalue, &address)) { if (capwap_address_from_string(addressvalue, &address)) {
if (address.ss_family == AF_INET) { if (address.ss.ss_family == AF_INET) {
/* Netmask */ /* Netmask */
jsonitem = json_object_object_get(jsonelement, "Netmask"); jsonitem = compat_json_object_object_get(jsonelement, "Netmask");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage netmask; union sockaddr_capwap netmask;
const char* netmaskvalue = json_object_get_string(jsonitem); const char* netmaskvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(netmaskvalue, &netmask)) { if (capwap_address_from_string(netmaskvalue, &netmask)) {
if (netmask.ss_family == AF_INET) { if (netmask.ss.ss_family == AF_INET) {
/* Gateway */ /* Gateway */
jsonitem = json_object_object_get(jsonelement, "Gateway"); jsonitem = compat_json_object_object_get(jsonelement, "Gateway");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
struct sockaddr_storage gateway; union sockaddr_capwap gateway;
const char* gatewayvalue = json_object_get_string(jsonitem); const char* gatewayvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(gatewayvalue, &gateway)) { if (capwap_address_from_string(gatewayvalue, &gateway)) {
if (gateway.ss_family == AF_INET) { if (gateway.ss.ss_family == AF_INET) {
/* Static */ /* Static */
jsonitem = json_object_object_get(jsonelement, "Static"); jsonitem = compat_json_object_object_get(jsonelement, "Static");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) {
int value = json_object_get_int(jsonitem); int value = json_object_get_int(jsonitem);
struct capwap_wtpstaticipaddress_element responsewtpstaticipaddress; struct capwap_wtpstaticipaddress_element responsewtpstaticipaddress;
memcpy(&responsewtpstaticipaddress.address, &((struct sockaddr_in*)&address)->sin_addr, sizeof(struct in_addr)); memcpy(&responsewtpstaticipaddress.address, &address.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.netmask, &((struct sockaddr_in*)&netmask)->sin_addr, sizeof(struct in_addr)); memcpy(&responsewtpstaticipaddress.netmask, &netmask.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.gateway, &((struct sockaddr_in*)&gateway)->sin_addr, sizeof(struct in_addr)); memcpy(&responsewtpstaticipaddress.gateway, &gateway.sin.sin_addr, sizeof(struct in_addr));
responsewtpstaticipaddress.staticip = (uint8_t)value; responsewtpstaticipaddress.staticip = (uint8_t)value;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPSTATICIPADDRESS, &responsewtpstaticipaddress); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPSTATICIPADDRESS, &responsewtpstaticipaddress);
@ -710,7 +708,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
ac_json_ieee80211_init(&wtpradio); ac_json_ieee80211_init(&wtpradio);
/* Parsing SOAP response */ /* Parsing SOAP response */
jsonelement = json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT); jsonelement = compat_json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
if (jsonelement) { if (jsonelement) {
if (ac_json_ieee80211_parsingjson(&wtpradio, jsonelement)) { if (ac_json_ieee80211_parsingjson(&wtpradio, jsonelement)) {
/* Add IEEE802.11 message elements to packet */ /* Add IEEE802.11 message elements to packet */
@ -777,11 +775,11 @@ void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_p
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Configure response to WTP */ /* Send Configure response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */ /* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send configuration status response packet"); capwap_logging_debug("Warning: error to send configuration status response packet");
} }
@ -789,7 +787,7 @@ void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_p
/* Change state */ /* Change state */
if (CAPWAP_RESULTCODE_OK(result)) { if (CAPWAP_RESULTCODE_OK(result)) {
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_STATE); ac_dfa_change_state(session, CAPWAP_DATA_CHECK_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_CHANGE_STATE_PENDING_INTERVAL, ac_dfa_state_datacheck_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_CHANGE_STATE_PENDING_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else { } else {
ac_session_teardown(session); ac_session_teardown(session);
} }

View File

@ -172,11 +172,6 @@ static uint32_t ac_dfa_state_datacheck_create_response(struct ac_session_t* sess
return CAPWAP_RESULTCODE_SUCCESS; return CAPWAP_RESULTCODE_SUCCESS;
} }
/* */
void ac_dfa_state_datacheck_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Configure timeout */
}
/* */ /* */
void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet) { void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
struct ac_soap_response* response; struct ac_soap_response* response;
@ -196,6 +191,13 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
if (response) { if (response) {
result = ac_dfa_state_datacheck_create_response(session, packet, response, txmngpacket); result = ac_dfa_state_datacheck_create_response(session, packet, response, txmngpacket);
ac_soapclient_free_response(response); ac_soapclient_free_response(response);
/* Create data session */
if (CAPWAP_RESULTCODE_OK(result)) {
if (ac_kmod_new_datasession(&session->sessionid, session->mtu)) {
result = CAPWAP_RESULTCODE_FAILURE;
}
}
} }
/* With error add result code message element */ /* With error add result code message element */
@ -220,11 +222,11 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Change event response to WTP */ /* Send Change event response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */ /* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send change event response packet"); capwap_logging_debug("Warning: error to send change event response packet");
} }
@ -232,15 +234,9 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
/* Change state */ /* Change state */
if (CAPWAP_RESULTCODE_OK(result)) { if (CAPWAP_RESULTCODE_OK(result)) {
ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_RUN_STATE); ac_dfa_change_state(session, CAPWAP_DATA_CHECK_TO_RUN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DATA_CHECK_INTERVAL, ac_dfa_state_datacheck_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DATA_CHECK_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
capwap_timeout_set(session->timeout, session->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else { } else {
ac_session_teardown(session); ac_session_teardown(session);
} }
} }
/* */
void ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
ASSERT(session != NULL);
ac_session_teardown(session);
}

View File

@ -3,60 +3,21 @@
#include "capwap_array.h" #include "capwap_array.h"
#include "ac_session.h" #include "ac_session.h"
/* DTLS BIO send */
static int ac_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_session_t* session = (struct ac_session_t*)param;
ASSERT(dtls->session == CAPWAP_DTLS_CONTROL_SESSION);
return capwap_sendto(session->connection.socket.socket[session->connection.socket.type], buffer, length, &session->connection.localaddr, &session->connection.remoteaddr);
}
/* DTLS BIO Data send */
static int ac_bio_data_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param;
ASSERT(dtls->session == CAPWAP_DTLS_DATA_SESSION);
return capwap_sendto(sessiondata->connection.socket.socket[sessiondata->connection.socket.type], buffer, length, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr);
}
/* */
void ac_dtls_setup_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Configure timeout */
}
/* */ /* */
int ac_dtls_setup(struct ac_session_t* session) { int ac_dtls_setup(struct ac_session_t* session) {
ASSERT(session != NULL); ASSERT(session != NULL);
/* Create DTLS session */ /* Create DTLS session */
if (!capwap_crypt_createsession(&session->dtls, CAPWAP_DTLS_CONTROL_SESSION, &g_ac.dtlscontext, ac_bio_send, session)) { if (!capwap_crypt_createsession(&session->dtls, &g_ac.dtlscontext)) {
return 0; return 0;
} }
if (capwap_crypt_open(&session->dtls, &session->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) { if (capwap_crypt_open(&session->dtls) == CAPWAP_HANDSHAKE_ERROR) {
return 0; return 0;
} }
/* Wait DTLS handshake complete */ /* Wait DTLS handshake complete */
ac_dfa_change_state(session, CAPWAP_DTLS_CONNECT_STATE); ac_dfa_change_state(session, CAPWAP_DTLS_CONNECT_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DTLS_INTERVAL, ac_dtls_setup_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DTLS_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
return 1;
}
/* */
int ac_dtls_data_setup(struct ac_session_data_t* sessiondata) {
ASSERT(sessiondata != NULL);
/* Create DTLS session */
if (!capwap_crypt_createsession(&sessiondata->dtls, CAPWAP_DTLS_DATA_SESSION, &g_ac.dtlscontext, ac_bio_data_send, sessiondata)) {
return 0;
}
if (capwap_crypt_open(&sessiondata->dtls, &sessiondata->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) {
return 0;
}
return 1; return 1;
} }

View File

@ -403,7 +403,7 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
ac_json_ieee80211_init(&wtpradio); ac_json_ieee80211_init(&wtpradio);
/* */ /* */
jsonelement = json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT); jsonelement = compat_json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
if (jsonelement) { if (jsonelement) {
ac_json_ieee80211_parsingjson(&wtpradio, jsonelement); ac_json_ieee80211_parsingjson(&wtpradio, jsonelement);
} }
@ -431,13 +431,13 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
for (item = controllist->first; item != NULL; item = item->next) { for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item; struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) { if (sessioncontrol->localaddress.ss.ss_family == AF_INET) {
struct capwap_controlipv4_element element; struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr)); memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count; element.wtpcount = sessioncontrol->count;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element);
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) { } else if (sessioncontrol->localaddress.ss.ss_family == AF_INET6) {
struct capwap_controlipv6_element element; struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr)); memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
@ -449,22 +449,22 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
capwap_list_free(controllist); capwap_list_free(controllist);
/* CAPWAP Local IP Address */ /* CAPWAP Local IP Address */
if (session->connection.localaddr.ss_family == AF_INET) { if (session->dtls.localaddr.ss.ss_family == AF_INET) {
struct capwap_localipv4_element addr; struct capwap_localipv4_element addr;
memcpy(&addr.address, &((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, sizeof(struct in_addr)); memcpy(&addr.address, &session->dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr);
} else if (session->connection.localaddr.ss_family == AF_INET6) { } else if (session->dtls.localaddr.ss.ss_family == AF_INET6) {
struct capwap_localipv6_element addr; struct capwap_localipv6_element addr;
memcpy(&addr.address, &((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, sizeof(struct in6_addr)); memcpy(&addr.address, &session->dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr);
} }
/* ACIPv4List */ /* ACIPv4List */
jsonelement = NULL; jsonelement = NULL;
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv4List"); jsonelement = compat_json_object_object_get(jsonroot, "ACIPv4List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement); length = json_object_array_length(jsonelement);
} else { } else {
@ -484,17 +484,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem; struct json_object* jsonitem;
/* ACIPAddress */ /* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress"); jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem); const char* value = json_object_get_string(jsonitem);
if (value) { if (value) {
struct sockaddr_storage address; union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) { if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */ /* Accept only IPv4 address */
if (address.ss_family == AF_INET) { if (address.ss.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count); struct in_addr* responseaddress_in = (struct in_addr*)capwap_array_get_item_pointer(responseacipv4list->addresses, responseacipv4list->addresses->count);
memcpy(responseaddress_in, &address_in->sin_addr, sizeof(struct in_addr)); memcpy(responseaddress_in, &address.sin.sin_addr, sizeof(struct in_addr));
} }
} }
} }
@ -515,7 +514,7 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
/* ACIPv6List */ /* ACIPv6List */
jsonelement = NULL; jsonelement = NULL;
if (jsonroot) { if (jsonroot) {
jsonelement = json_object_object_get(jsonroot, "ACIPv6List"); jsonelement = compat_json_object_object_get(jsonroot, "ACIPv6List");
if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) { if (jsonelement && (json_object_get_type(jsonelement) == json_type_array)) {
length = json_object_array_length(jsonelement); length = json_object_array_length(jsonelement);
} else { } else {
@ -536,17 +535,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem; struct json_object* jsonitem;
/* ACIPAddress */ /* ACIPAddress */
jsonitem = json_object_object_get(jsonvalue, "ACIPAddress"); jsonitem = compat_json_object_object_get(jsonvalue, "ACIPAddress");
if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) {
const char* value = json_object_get_string(jsonitem); const char* value = json_object_get_string(jsonitem);
if (value) { if (value) {
struct sockaddr_storage address; union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) { if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */ /* Accept only IPv6 address */
if (address.ss_family == AF_INET6) { if (address.ss.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count); struct in6_addr* responseaddress_in6 = (struct in6_addr*)capwap_array_get_item_pointer(responseacipv6list->addresses, responseacipv6list->addresses->count);
memcpy(responseaddress_in6, &address_in6->sin6_addr, sizeof(struct in6_addr)); memcpy(responseaddress_in6, &address.sin6.sin6_addr, sizeof(struct in6_addr));
} }
} }
} }
@ -578,11 +576,6 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
return CAPWAP_RESULTCODE_SUCCESS; return CAPWAP_RESULTCODE_SUCCESS;
} }
/* */
void ac_dfa_state_join_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
ac_session_teardown((struct ac_session_t*)context); /* Join timeout */
}
/* */ /* */
void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet) { void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet) {
unsigned short binding; unsigned short binding;
@ -620,6 +613,7 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE; resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE;
} }
} else { } else {
capwap_logging_info("WTP Id %s already used in another session", wtpid);
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE; resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_UNKNOWN_SOURCE;
} }
@ -628,10 +622,15 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
session->wtpid = wtpid; session->wtpid = wtpid;
memcpy(&session->sessionid, sessionid, sizeof(struct capwap_sessionid_element)); memcpy(&session->sessionid, sessionid, sizeof(struct capwap_sessionid_element));
session->binding = binding; session->binding = binding;
} else { } else if (wtpid) {
capwap_free(wtpid); capwap_free(wtpid);
} }
} else { } else {
char sessionname[33];
capwap_sessionid_printf(sessionid, sessionname);
capwap_logging_info("Session Id %s already used in another session", sessionname);
resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_ID_ALREADY_IN_USE; resultcode.code = CAPWAP_RESULTCODE_JOIN_FAILURE_ID_ALREADY_IN_USE;
} }
} else { } else {
@ -668,14 +667,14 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* Send Join response to WTP */ /* Send Join response to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
if (CAPWAP_RESULTCODE_OK(resultcode.code)) { if (CAPWAP_RESULTCODE_OK(resultcode.code)) {
ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE); ac_dfa_change_state(session, CAPWAP_POSTJOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else { } else {
ac_session_teardown(session); ac_session_teardown(session);
} }

View File

@ -51,11 +51,19 @@ static int receive_echo_request(struct ac_session_t* session, struct capwap_pars
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
#ifdef DEBUG
{
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Send Echo Response to %s", sessionname);
}
#endif
/* Send Configure response to WTP */ /* Send Configure response to WTP */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
/* Response is already created and saved. When receive a re-request, DFA autoresponse */ /* Response is already created and saved. When receive a re-request, DFA autoresponse */
capwap_logging_debug("Warning: error to send echo response packet"); capwap_logging_debug("Warning: error to send echo response packet");
} }
@ -78,7 +86,7 @@ static void execute_ieee80211_wlan_configuration_addwlan(struct ac_session_t* se
wlan = ac_wlans_create_bssid(&session->wlans->devices[assignbssid->radioid - 1], assignbssid->wlanid, assignbssid->bssid, addwlan); wlan = ac_wlans_create_bssid(&session->wlans->devices[assignbssid->radioid - 1], assignbssid->wlanid, assignbssid->bssid, addwlan);
/* Assign BSSID to session */ /* Assign BSSID to session */
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_ASSIGN_BSSID, 0, &wlan, sizeof(struct ac_wlan*)); ac_wlans_assign_bssid(session, wlan);
} }
} }
@ -109,7 +117,7 @@ static void receive_ieee80211_wlan_configuration_response(struct ac_session_t* s
if (CAPWAP_RESULTCODE_OK(resultcode->code)) { if (CAPWAP_RESULTCODE_OK(resultcode->code)) {
rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket); rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket);
if (rxmngrequestpacket) { if (rxmngrequestpacket) {
if (capwap_parsing_packet(rxmngrequestpacket, NULL, &requestpacket) == PARSING_COMPLETE) { if (capwap_parsing_packet(rxmngrequestpacket, &requestpacket) == PARSING_COMPLETE) {
/* Detect type of IEEE802.11 WLAN Configuration Request */ /* Detect type of IEEE802.11 WLAN Configuration Request */
if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_80211_ADD_WLAN)) { if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_80211_ADD_WLAN)) {
execute_ieee80211_wlan_configuration_addwlan(session, packet, &requestpacket); execute_ieee80211_wlan_configuration_addwlan(session, packet, &requestpacket);
@ -134,10 +142,10 @@ static void receive_ieee80211_wlan_configuration_response(struct ac_session_t* s
/* */ /* */
static void execute_ieee80211_station_configuration_response_addstation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) { static void execute_ieee80211_station_configuration_response_addstation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) {
struct ac_wlan* wlan;
struct ac_station* station;
struct capwap_addstation_element* addstation; struct capwap_addstation_element* addstation;
struct ac_notify_add_station_status notify;
struct capwap_80211_station_element* station80211; struct capwap_80211_station_element* station80211;
unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header);
struct capwap_resultcode_element* resultcode; struct capwap_resultcode_element* resultcode;
/* */ /* */
@ -145,39 +153,47 @@ static void execute_ieee80211_station_configuration_response_addstation(struct a
addstation = (struct capwap_addstation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_ADDSTATION); addstation = (struct capwap_addstation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_ADDSTATION);
/* */ /* */
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { if (GET_WBID_HEADER(packet->rxmngpacket->header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
station80211 = (struct capwap_80211_station_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_80211_STATION); station80211 = (struct capwap_80211_station_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_80211_STATION);
if (station80211) { if (station80211) {
memset(&notify, 0, sizeof(struct ac_notify_add_station_status)); wlan = ac_wlans_get_bssid_with_wlanid(session, station80211->radioid, station80211->wlanid);
if (wlan) {
station = ac_stations_get_station(session, station80211->radioid, wlan->address, addstation->address);
if (station) {
if (CAPWAP_RESULTCODE_OK(resultcode->code)) {
capwap_logging_info("Authorized station: %s", station->addrtext);
notify.radioid = station80211->radioid; /* */
notify.wlanid = station80211->wlanid; station->flags |= AC_STATION_FLAGS_AUTHORIZED;
memcpy(notify.address, addstation->address, MACADDRESS_EUI48_LENGTH); capwap_timeout_deletetimer(session->timeout, station->idtimeout);
notify.statuscode = resultcode->code; station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} else {
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_ADD_STATION_STATUS, 0, (void*)&notify, sizeof(struct ac_notify_add_station_status)); ac_stations_delete_station(session, station);
}
}
}
} }
} }
} }
/* */ /* */
static void execute_ieee80211_station_configuration_response_deletestation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) { static void execute_ieee80211_station_configuration_response_deletestation(struct ac_session_t* session, struct capwap_parsed_packet* packet, struct capwap_parsed_packet* requestpacket) {
struct capwap_deletestation_element* deletestation; struct ac_station* station;
struct ac_notify_delete_station_status notify;
struct capwap_resultcode_element* resultcode; struct capwap_resultcode_element* resultcode;
struct capwap_deletestation_element* deletestation;
/* */ /* */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE); resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
deletestation = (struct capwap_deletestation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_DELETESTATION); deletestation = (struct capwap_deletestation_element*)capwap_get_message_element_data(requestpacket, CAPWAP_ELEMENT_DELETESTATION);
/* */ /* */
memset(&notify, 0, sizeof(struct ac_notify_delete_station_status)); station = ac_stations_get_station(session, deletestation->radioid, NULL, deletestation->address);
if (station) {
capwap_logging_info("Deauthorized station: %s with %d result code", station->addrtext, (int)resultcode->code);
notify.radioid = deletestation->radioid; /* */
memcpy(notify.address, deletestation->address, MACADDRESS_EUI48_LENGTH); ac_stations_delete_station(session, station);
notify.statuscode = resultcode->code; }
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS, 0, (void*)&notify, sizeof(struct ac_notify_delete_station_status));
} }
/* */ /* */
@ -187,7 +203,7 @@ static void receive_ieee80211_station_configuration_response(struct ac_session_t
/* Parsing request message */ /* Parsing request message */
rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket); rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket);
if (capwap_parsing_packet(rxmngrequestpacket, NULL, &requestpacket) == PARSING_COMPLETE) { if (capwap_parsing_packet(rxmngrequestpacket, &requestpacket) == PARSING_COMPLETE) {
if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_ADDSTATION)) { if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_ADDSTATION)) {
execute_ieee80211_station_configuration_response_addstation(session, packet, &requestpacket); execute_ieee80211_station_configuration_response_addstation(session, packet, &requestpacket);
} else if (capwap_get_message_element_data(&requestpacket, CAPWAP_ELEMENT_DELETESTATION)) { } else if (capwap_get_message_element_data(&requestpacket, CAPWAP_ELEMENT_DELETESTATION)) {
@ -223,6 +239,14 @@ void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet*
} }
case CAPWAP_ECHO_REQUEST: { case CAPWAP_ECHO_REQUEST: {
#ifdef DEBUG
{
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Receive Echo Request from %s", sessionname);
}
#endif
if (!receive_echo_request(session, packet)) { if (!receive_echo_request(session, packet)) {
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else { } else {

View File

@ -19,32 +19,32 @@ struct ac_discovery_t {
struct ac_discovery_packet { struct ac_discovery_packet {
int sendsock; int sendsock;
struct sockaddr_storage sender; union sockaddr_capwap sender;
char data[0]; char data[0];
}; };
static struct ac_discovery_t g_ac_discovery; static struct ac_discovery_t g_ac_discovery;
/* */ /* */
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender) { void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender) {
struct capwap_list_item* item; struct capwap_list_item* item;
struct ac_discovery_packet* packet; struct ac_discovery_packet* packet;
ASSERT(buffer != NULL); ASSERT(buffer != NULL);
ASSERT(buffersize > 0); ASSERT(buffersize > 0);
ASSERT(sock >= 0); ASSERT(sock >= 0);
ASSERT(sender != NULL); ASSERT(sender != NULL);
/* TODO: mettere un history delle discovery request già processate per non eseguirle di nuovo */ /* 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 */ /* L'elemento deve rimanere per la durata minima di una discovery request */
/* Copy packet */ /* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize); item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize);
packet = (struct ac_discovery_packet*)item->item; packet = (struct ac_discovery_packet*)item->item;
packet->sendsock = sock; packet->sendsock = sock;
memcpy(&packet->sender, sender, sizeof(struct sockaddr_storage)); memcpy(&packet->sender, sender, sizeof(union sockaddr_capwap));
memcpy(packet->data, buffer, buffersize); memcpy(packet->data, buffer, buffersize);
/* Append to packets list */ /* Append to packets list */
capwap_lock_enter(&g_ac_discovery.packetslock); capwap_lock_enter(&g_ac_discovery.packetslock);
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item); capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
@ -95,13 +95,13 @@ static struct capwap_packet_txmng* ac_create_discovery_response(struct capwap_pa
for (item = controllist->first; item != NULL; item = item->next) { for (item = controllist->first; item != NULL; item = item->next) {
struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item; struct ac_session_control* sessioncontrol = (struct ac_session_control*)item->item;
if (sessioncontrol->localaddress.ss_family == AF_INET) { if (sessioncontrol->localaddress.ss.ss_family == AF_INET) {
struct capwap_controlipv4_element element; struct capwap_controlipv4_element element;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr)); memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count; element.wtpcount = sessioncontrol->count;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_CONTROLIPV4, &element);
} else if (sessioncontrol->localaddress.ss_family == AF_INET6) { } else if (sessioncontrol->localaddress.ss.ss_family == AF_INET6) {
struct capwap_controlipv6_element element; struct capwap_controlipv6_element element;
memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr)); memcpy(&element.address, &((struct sockaddr_in6*)&sessioncontrol->localaddress)->sin6_addr, sizeof(struct in6_addr));
@ -156,12 +156,12 @@ static void ac_discovery_run(void) {
sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet); sizedata = itempacket->itemsize - sizeof(struct ac_discovery_packet);
/* Accept only discovery request don't fragment */ /* Accept only discovery request don't fragment */
rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET); rxmngpacket = capwap_packet_rxmng_create_message();
if (capwap_packet_rxmng_add_recv_packet(rxmngpacket, acpacket->data, sizedata) == CAPWAP_RECEIVE_COMPLETE_PACKET) { if (capwap_packet_rxmng_add_recv_packet(rxmngpacket, acpacket->data, sizedata) == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Validate message */ /* Validate message */
if (capwap_check_message_type(rxmngpacket) == VALID_MESSAGE_TYPE) { if (capwap_check_message_type(rxmngpacket) == VALID_MESSAGE_TYPE) {
/* Parsing packet */ /* Parsing packet */
if (capwap_parsing_packet(rxmngpacket, NULL, &packet) == PARSING_COMPLETE) { if (capwap_parsing_packet(rxmngpacket, &packet) == PARSING_COMPLETE) {
/* Validate packet */ /* Validate packet */
if (!capwap_validate_parsed_packet(&packet, NULL)) { if (!capwap_validate_parsed_packet(&packet, NULL)) {
struct capwap_packet_txmng* txmngpacket; struct capwap_packet_txmng* txmngpacket;
@ -185,7 +185,7 @@ static void ac_discovery_run(void) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send discovery response to WTP */ /* Send discovery response to WTP */
if (!capwap_sendto_fragmentpacket(acpacket->sendsock, responsefragmentpacket, NULL, &acpacket->sender)) { if (!capwap_sendto_fragmentpacket(acpacket->sendsock, responsefragmentpacket, &acpacket->sender)) {
capwap_logging_debug("Warning: error to send discovery response packet"); capwap_logging_debug("Warning: error to send discovery response packet");
} }

View File

@ -3,6 +3,6 @@
int ac_discovery_start(void); int ac_discovery_start(void);
void ac_discovery_stop(void); void ac_discovery_stop(void);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender); void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender);
#endif /* __AC_DISCOVERY_HEADER__ */ #endif /* __AC_DISCOVERY_HEADER__ */

View File

@ -104,7 +104,7 @@ void ac_msgqueue_notify_closethread(pthread_t threadid) {
} }
/* */ /* */
static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) { static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) {
int index; int index;
ASSERT(fds); ASSERT(fds);
@ -113,8 +113,7 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct socka
ASSERT(buffer != NULL); ASSERT(buffer != NULL);
ASSERT(size != NULL); ASSERT(size != NULL);
ASSERT(*size > 0); ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL); ASSERT(fromaddr != NULL);
ASSERT(recvtoaddr != NULL);
/* Wait packet */ /* Wait packet */
index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, NULL); index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, NULL);
@ -146,7 +145,7 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct socka
} }
/* Receive packet */ /* Receive packet */
if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { if (capwap_recvfrom(fds->fdspoll[index].fd, buffer, size, fromaddr, toaddr)) {
return CAPWAP_RECV_ERROR_SOCKET; return CAPWAP_RECV_ERROR_SOCKET;
} }
@ -175,28 +174,6 @@ static void ac_session_add_packet(struct ac_session_t* session, char* buffer, in
capwap_lock_exit(&session->sessionlock); capwap_lock_exit(&session->sessionlock);
} }
/* Add packet to session data */
static void ac_session_data_add_packet(struct ac_session_data_t* sessiondata, char* buffer, int size, int plainbuffer) {
struct capwap_list_item* item;
struct ac_packet* packet;
ASSERT(sessiondata != 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(&sessiondata->sessionlock);
capwap_itemlist_insert_after(sessiondata->packets, NULL, item);
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Add action to session */ /* Add action to session */
void ac_session_send_action(struct ac_session_t* session, long action, long param, const void* data, long length) { void ac_session_send_action(struct ac_session_t* session, long action, long param, const void* data, long length) {
struct capwap_list_item* item; struct capwap_list_item* item;
@ -239,52 +216,8 @@ void ac_session_send_action(struct ac_session_t* session, long action, long para
capwap_rwlock_exit(&g_ac.sessionslock); capwap_rwlock_exit(&g_ac.sessionslock);
} }
/* Add action to session data */
void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length) {
struct capwap_list_item* item;
struct ac_session_action* actionsession;
struct capwap_list_item* search;
ASSERT(sessiondata != NULL);
ASSERT(length >= 0);
/* */
item = capwap_itemlist_create(sizeof(struct ac_session_action) + length);
actionsession = (struct ac_session_action*)item->item;
actionsession->action = action;
actionsession->param = param;
actionsession->length = length;
if (length > 0) {
ASSERT(data != NULL);
memcpy(actionsession->data, data, length);
}
/* Validate session data before use */
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
if (sessiondata == (struct ac_session_data_t*)search->item) {
/* Append to actions list */
capwap_lock_enter(&sessiondata->sessionlock);
capwap_itemlist_insert_after(sessiondata->action, NULL, item);
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
break;
}
/* */
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
}
/* Find AC sessions */ /* Find AC sessions */
static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_storage* address) { static struct ac_session_t* ac_search_session_from_wtpaddress(union sockaddr_capwap* address) {
struct ac_session_t* result = NULL; struct ac_session_t* result = NULL;
struct capwap_list_item* search; struct capwap_list_item* search;
@ -297,7 +230,7 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
struct ac_session_t* session = (struct ac_session_t*)search->item; struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL); ASSERT(session != NULL);
if (!capwap_compare_ip(address, &session->connection.remoteaddr)) { if (!capwap_compare_ip(address, &session->dtls.peeraddr)) {
/* Increment session count */ /* Increment session count */
capwap_lock_enter(&session->sessionlock); capwap_lock_enter(&session->sessionlock);
session->count++; session->count++;
@ -317,40 +250,6 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
return result; return result;
} }
/* Find AC sessions data */
static struct ac_session_data_t* ac_search_session_data_from_wtpaddress(struct sockaddr_storage* address) {
struct ac_session_data_t* result = NULL;
struct capwap_list_item* search;
ASSERT(address != NULL);
capwap_rwlock_rdlock(&g_ac.sessionslock);
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
ASSERT(sessiondata != NULL);
if (!capwap_compare_ip(address, &sessiondata->connection.remoteaddr)) {
/* Increment session data count */
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count++;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
/* */
result = sessiondata;
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
/* Find session from wtp id */ /* Find session from wtp id */
struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) { struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) {
struct ac_session_t* result = NULL; struct ac_session_t* result = NULL;
@ -365,7 +264,41 @@ struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) {
struct ac_session_t* session = (struct ac_session_t*)search->item; struct ac_session_t* session = (struct ac_session_t*)search->item;
ASSERT(session != NULL); ASSERT(session != NULL);
if (!strcmp(session->wtpid, wtpid)) { if (session->wtpid && !strcmp(session->wtpid, wtpid)) {
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
capwap_event_signal(&session->changereference);
capwap_lock_exit(&session->sessionlock);
/* */
result = session;
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
return result;
}
/* Find session from wtp id */
struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid) {
struct ac_session_t* result = NULL;
struct capwap_list_item* search;
ASSERT(sessionid != NULL);
capwap_rwlock_rdlock(&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))) {
/* Increment session count */ /* Increment session count */
capwap_lock_enter(&session->sessionlock); capwap_lock_enter(&session->sessionlock);
session->count++; session->count++;
@ -468,14 +401,6 @@ void ac_session_close(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock); capwap_lock_exit(&session->sessionlock);
} }
/* */
void ac_session_data_close(struct ac_session_data_t* sessiondata) {
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->running = 0;
capwap_event_signal(&sessiondata->waitpacket);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Close sessions */ /* Close sessions */
static void ac_close_sessions() { static void ac_close_sessions() {
struct capwap_list_item* search; struct capwap_list_item* search;
@ -493,45 +418,18 @@ static void ac_close_sessions() {
search = search->next; search = search->next;
} }
/* Session data */
search = g_ac.sessionsdata->first;
while (search != NULL) {
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)search->item;
ASSERT(sessiondata != NULL);
ac_session_data_close(sessiondata);
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock); capwap_rwlock_exit(&g_ac.sessionslock);
} }
/* Detect data channel */
static int ac_is_plain_datachannel(void* buffer, int buffersize) {
struct capwap_preamble* preamble = (struct capwap_preamble*)buffer;
ASSERT(buffer != NULL);
ASSERT(buffersize > sizeof(struct capwap_preamble));
if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED) != 0)) {
return 1;
} else if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && ((g_ac.descriptor.dtlspolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) != 0)) {
return 0;
}
return -1;
}
/* Create new session */ /* Create new session */
static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock) { static struct ac_session_t* ac_create_session(int sock, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) {
int result; int result;
struct capwap_list_item* itemlist; struct capwap_list_item* itemlist;
struct ac_session_t* session; struct ac_session_t* session;
ASSERT(acaddress != NULL); ASSERT(sock >= 0);
ASSERT(wtpaddress != NULL); ASSERT(fromaddr != NULL);
ASSERT(sock != NULL); ASSERT(toaddr != NULL);
/* Create new session */ /* Create new session */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_t)); itemlist = capwap_itemlist_create(sizeof(struct ac_session_t));
@ -541,9 +439,8 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
session->itemlist = itemlist; session->itemlist = itemlist;
session->running = 1; session->running = 1;
memcpy(&session->connection.socket, sock, sizeof(struct capwap_socket)); /* */
memcpy(&session->connection.localaddr, acaddress, sizeof(struct sockaddr_storage)); capwap_crypt_setconnection(&session->dtls, sock, toaddr, fromaddr);
memcpy(&session->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage));
/* */ /* */
ac_wlans_init(session); ac_wlans_init(session);
@ -555,21 +452,19 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
/* */ /* */
session->timeout = capwap_timeout_init(); session->timeout = capwap_timeout_init();
session->idtimercontrol = capwap_timeout_createtimer(session->timeout); session->idtimercontrol = capwap_timeout_createtimer(session->timeout);
session->idtimerkeepalivedead = capwap_timeout_createtimer(session->timeout);
/* Duplicate state for DFA */ /* Duplicate state for DFA */
memcpy(&session->dfa, &g_ac.dfa, sizeof(struct ac_state)); memcpy(&session->dfa, &g_ac.dfa, sizeof(struct ac_state));
session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses);
session->dfa.acipv6list.addresses = capwap_array_clone(g_ac.dfa.acipv6list.addresses);
/* Add default AC list if empty*/ session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses);
if ((session->dfa.acipv4list.addresses->count == 0) && (session->dfa.acipv6list.addresses->count == 0)) { if (!session->dfa.acipv4list.addresses->count && (session->dtls.localaddr.ss.ss_family == AF_INET)) {
if (acaddress->ss_family == AF_INET) { memcpy(capwap_array_get_item_pointer(session->dfa.acipv4list.addresses, 0), &session->dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
struct in_addr* acip = (struct in_addr*)capwap_array_get_item_pointer(session->dfa.acipv4list.addresses, 0); }
memcpy(acip, &((struct sockaddr_in*)acaddress)->sin_addr, sizeof(struct in_addr));
} else if (acaddress->ss_family == AF_INET6) { session->dfa.acipv6list.addresses = capwap_array_clone(g_ac.dfa.acipv6list.addresses);
struct in6_addr* acip = (struct in6_addr*)capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0); if (!session->dfa.acipv6list.addresses->count && (session->dtls.localaddr.ss.ss_family == AF_INET6)) {
memcpy(acip, &((struct sockaddr_in6*)acaddress)->sin6_addr, sizeof(struct in6_addr)); memcpy(capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0), &session->dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
}
} }
/* Init */ /* Init */
@ -610,73 +505,6 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
return session; return session;
} }
/* Create new session data */
static struct ac_session_data_t* ac_create_session_data(struct sockaddr_storage* wtpaddress, struct sockaddr_storage* acaddress, struct capwap_socket* sock, int plain) {
int result;
struct capwap_list_item* itemlist;
struct ac_session_data_t* sessiondata;
ASSERT(acaddress != NULL);
ASSERT(wtpaddress != NULL);
ASSERT(sock != NULL);
/* Create new session data */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_data_t));
sessiondata = (struct ac_session_data_t*)itemlist->item;
memset(sessiondata, 0, sizeof(struct ac_session_data_t));
/* */
sessiondata->itemlist = itemlist;
sessiondata->running = 1;
sessiondata->enabledtls = (plain ? 0 : 1);
/* */
sessiondata->count = 2;
capwap_event_init(&sessiondata->changereference);
/* */
sessiondata->timeout = capwap_timeout_init();
sessiondata->idtimercontrol = capwap_timeout_createtimer(sessiondata->timeout);
sessiondata->idtimerkeepalivedead = capwap_timeout_createtimer(sessiondata->timeout);
/* Connection info */
memcpy(&sessiondata->connection.socket, sock, sizeof(struct capwap_socket));
memcpy(&sessiondata->connection.localaddr, acaddress, sizeof(struct sockaddr_storage));
memcpy(&sessiondata->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage));
sessiondata->mtu = g_ac.mtu;
/* Init */
capwap_event_init(&sessiondata->waitpacket);
capwap_lock_init(&sessiondata->sessionlock);
sessiondata->action = capwap_list_create();
sessiondata->packets = capwap_list_create();
/* Update session data list */
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_insert_after(g_ac.sessionsdata, NULL, itemlist);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Create thread */
result = pthread_create(&sessiondata->threadid, NULL, ac_session_data_thread, (void*)sessiondata);
if (!result) {
struct ac_session_thread_t* sessionthread;
/* Keeps trace of active threads */
itemlist = capwap_itemlist_create(sizeof(struct ac_session_thread_t));
sessionthread = (struct ac_session_thread_t*)itemlist->item;
sessionthread->threadid = sessiondata->threadid;
/* */
capwap_itemlist_insert_after(g_ac.sessionsthread, NULL, itemlist);
} else {
capwap_logging_fatal("Unable create session data thread, error code %d", result);
capwap_exit(CAPWAP_OUT_OF_MEMORY);
}
return sessiondata;
}
/* Release reference of session */ /* Release reference of session */
void ac_session_release_reference(struct ac_session_t* session) { void ac_session_release_reference(struct ac_session_t* session) {
ASSERT(session != NULL); ASSERT(session != NULL);
@ -688,17 +516,6 @@ void ac_session_release_reference(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock); capwap_lock_exit(&session->sessionlock);
} }
/* Release reference of session data */
void ac_session_data_release_reference(struct ac_session_data_t* sessiondata) {
ASSERT(sessiondata != NULL);
capwap_lock_enter(&sessiondata->sessionlock);
ASSERT(sessiondata->count > 0);
sessiondata->count--;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
}
/* Update statistics */ /* Update statistics */
void ac_update_statistics(void) { void ac_update_statistics(void) {
@ -816,15 +633,17 @@ int ac_execute(void) {
int index; int index;
int check; int check;
struct capwap_socket socket; union sockaddr_capwap fromaddr;
struct sockaddr_storage recvfromaddr; union sockaddr_capwap toaddr;
struct sockaddr_storage recvtoaddr; struct ac_session_t* session;
char buffer[CAPWAP_MAX_PACKET_SIZE]; char buffer[CAPWAP_MAX_PACKET_SIZE];
int buffersize; int buffersize;
struct ac_fds fds;
/* Set file descriptor pool */ /* Set file descriptor pool */
if (ac_execute_init_fdspool(&g_ac.fds, &g_ac.net, g_ac.fdmsgsessions[1]) <= 0) { if (ac_execute_init_fdspool(&fds, &g_ac.net, g_ac.fdmsgsessions[1]) <= 0) {
capwap_logging_debug("Unable to initialize file descriptor pool"); capwap_logging_debug("Unable to initialize file descriptor pool");
return AC_ERROR_SYSTEM_FAILER; return AC_ERROR_SYSTEM_FAILER;
} }
@ -837,14 +656,14 @@ int ac_execute(void) {
/* Start discovery thread */ /* Start discovery thread */
if (!ac_discovery_start()) { if (!ac_discovery_start()) {
ac_execute_free_fdspool(&g_ac.fds); ac_execute_free_fdspool(&fds);
capwap_logging_debug("Unable to start discovery thread"); capwap_logging_debug("Unable to start discovery thread");
return AC_ERROR_SYSTEM_FAILER; return AC_ERROR_SYSTEM_FAILER;
} }
/* Enable Backend Management */ /* Enable Backend Management */
if (!ac_backend_start()) { if (!ac_backend_start()) {
ac_execute_free_fdspool(&g_ac.fds); ac_execute_free_fdspool(&fds);
ac_discovery_stop(); ac_discovery_stop();
capwap_logging_error("Unable start backend management"); capwap_logging_error("Unable start backend management");
return AC_ERROR_SYSTEM_FAILER; return AC_ERROR_SYSTEM_FAILER;
@ -854,7 +673,7 @@ int ac_execute(void) {
while (g_ac.running) { while (g_ac.running) {
/* Receive packet */ /* Receive packet */
buffersize = sizeof(buffer); buffersize = sizeof(buffer);
index = ac_recvfrom(&g_ac.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr); index = ac_recvfrom(&fds, buffer, &buffersize, &fromaddr, &toaddr);
if (!g_ac.running) { if (!g_ac.running) {
capwap_logging_debug("Closing AC"); capwap_logging_debug("Closing AC");
break; break;
@ -862,119 +681,62 @@ int ac_execute(void) {
/* */ /* */
if (index >= 0) { if (index >= 0) {
/* Detect local address */ /* Search the AC session */
if (recvtoaddr.ss_family == AF_UNSPEC) { session = ac_search_session_from_wtpaddress(&fromaddr);
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_ac.net.bind_interface, (!(g_ac.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) { if (session) {
struct sockaddr_storage sockinfo; /* Add packet*/
socklen_t sockinfolen = sizeof(struct sockaddr_storage); ac_session_add_packet(session, buffer, buffersize, 0);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); /* Release reference */
if (getsockname(g_ac.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { ac_session_release_reference(session);
break; } else {
} unsigned short sessioncount;
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo)); /* TODO prevent dos attack add filtering ip for multiple error */
}
}
/* Retrieve network information */ /* Get current session number */
capwap_get_network_socket(&g_ac.net, &socket, g_ac.fds.fdspoll[index].fd); capwap_rwlock_rdlock(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* Search the AC session / session data */ /* */
if (socket.isctrlsocket) { if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) {
struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr); check = capwap_sanity_check(CAPWAP_UNDEF_STATE, buffer, buffersize, g_ac.enabledtls);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_header* header = (struct capwap_header*)buffer;
if (session) { /* Accepted only packet without fragmentation */
/* Add packet*/ if (!IS_FLAG_F_HEADER(header)) {
ac_session_add_packet(session, buffer, buffersize, 0); 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);
/* Release reference */ if (type == CAPWAP_DISCOVERY_REQUEST) {
ac_session_release_reference(session); ac_discovery_add_packet(buffer, buffersize, fds.fdspoll[index].fd, &fromaddr);
} else { } else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
unsigned short sessioncount; /* Create a new session */
session = ac_create_session(fds.fdspoll[index].fd, &fromaddr, &toaddr);
ac_session_add_packet(session, buffer, buffersize, 1);
/* TODO prevent dos attack add filtering ip for multiple error */ /* Release reference */
ac_session_release_reference(session);
/* Get current session number */
capwap_rwlock_rdlock(&g_ac.sessionslock);
sessioncount = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* */
if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) {
check = capwap_sanity_check(1, 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) {
ac_discovery_add_packet(buffer, buffersize, g_ac.fds.fdspoll[index].fd, &recvfromaddr);
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
ac_session_add_packet(session, buffer, buffersize, 1);
/* Release reference */
ac_session_release_reference(session);
}
} }
} }
} else if (check == CAPWAP_DTLS_PACKET) {
/* Before create new session check if receive DTLS Client Hello */
if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
/* Create a new session */
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
ac_session_add_packet(session, buffer, buffersize, 0);
/* Release reference */
ac_session_release_reference(session);
}
} }
} } else if (check == CAPWAP_DTLS_PACKET) {
} /* Before create new session check if receive DTLS Client Hello */
} else { if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
struct ac_session_data_t* sessiondata = ac_search_session_data_from_wtpaddress(&recvfromaddr); /* Create a new session */
session = ac_create_session(fds.fdspoll[index].fd, &fromaddr, &toaddr);
ac_session_add_packet(session, buffer, buffersize, 0);
if (sessiondata) { /* Release reference */
/* Add packet*/ ac_session_release_reference(session);
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
/* Release reference */
ac_session_data_release_reference(sessiondata);
} else {
int plain;
/* TODO prevent dos attack add filtering ip for multiple error */
/* Detect type data channel */
plain = ac_is_plain_datachannel(buffer, buffersize);
/* Before create new session check if receive DTLS Client Hello */
if (!plain) {
if (buffersize <= sizeof(struct capwap_dtls_header)) {
plain = -1;
} else if (!capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
plain = -1;
} }
} }
/* */
if (plain >= 0) {
/* Create a new session */
sessiondata = ac_create_session_data(&recvfromaddr, &recvtoaddr, &socket, plain);
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
/* Release reference */
ac_session_data_release_reference(sessiondata);
}
} }
} }
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE) || (index == AC_RECV_NOERROR_KMODEVENT)) { } else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE) || (index == AC_RECV_NOERROR_KMODEVENT)) {
/* Ignore recv */ /* Ignore recv */
continue; continue;
@ -1000,6 +762,6 @@ int ac_execute(void) {
ac_backend_free(); ac_backend_free();
/* Free file description pool */ /* Free file description pool */
ac_execute_free_fdspool(&g_ac.fds); ac_execute_free_fdspool(&fds);
return result; return result;
} }

View File

@ -3,7 +3,7 @@
#include "ac_wlans.h" #include "ac_wlans.h"
/* */ /* */
static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
@ -22,7 +22,7 @@ static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_data_t* ses
} }
/* */ /* */
static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
struct ac_station* station; struct ac_station* station;
@ -36,7 +36,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
/* */ /* */
if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_create_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa); station = ac_stations_create_station(session, radioid, mgmt->bssid, mgmt->sa);
if (!station || !station->wlan) { if (!station || !station->wlan) {
return; return;
} }
@ -46,7 +46,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
/* A station is removed if the association does not complete within a given period of time */ /* A station is removed if the association does not complete within a given period of time */
station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE;
station->idtimeout = capwap_timeout_set(sessiondata->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, sessiondata->session); station->idtimeout = capwap_timeout_set(session->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, session);
/* */ /* */
wlan = station->wlan; wlan = station->wlan;
@ -94,20 +94,20 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
responselength = ieee80211_create_authentication_response(buffer, sizeof(buffer), &ieee80211_params); responselength = ieee80211_create_authentication_response(buffer, sizeof(buffer), &ieee80211_params);
if (responselength > 0) { if (responselength > 0) {
/* Send authentication response */ /* Send authentication response */
if (!ac_session_data_send_data_packet(sessiondata, wlan->device->radioid, wlan->wlanid, buffer, responselength, 1)) { if (!ac_kmod_send_data(&session->sockaddrdata.ss, wlan->device->radioid, session->binding, buffer, responselength)) {
capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode); capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode);
station->flags |= AC_STATION_FLAGS_AUTHENTICATED; station->flags |= AC_STATION_FLAGS_AUTHENTICATED;
} else { } else {
capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext); capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
} }
} else { } else {
capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext); capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
} }
} }
} else if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { } else if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->da); station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da);
if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) {
uint16_t algorithm; uint16_t algorithm;
uint16_t transactionseqnumber; uint16_t transactionseqnumber;
@ -135,7 +135,7 @@ static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_data_t* se
} }
/* */ /* */
static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
struct ac_station* station; struct ac_station* station;
@ -149,7 +149,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Get station */ /* Get station */
if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->sa); station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->sa);
if (!station || !station->wlan) { if (!station || !station->wlan) {
return; return;
} }
@ -162,7 +162,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) { if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) {
/* Invalid station, delete station */ /* Invalid station, delete station */
capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
return; return;
} }
@ -192,7 +192,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Parsing Information Elements */ /* Parsing Information Elements */
if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) {
capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
return; return;
} }
@ -236,19 +236,19 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
responselength = ieee80211_create_associationresponse_response(buffer, sizeof(buffer), &ieee80211_params); responselength = ieee80211_create_associationresponse_response(buffer, sizeof(buffer), &ieee80211_params);
if (responselength > 0) { if (responselength > 0) {
/* Send association response */ /* Send association response */
if (!ac_session_data_send_data_packet(sessiondata, wlan->device->radioid, wlan->wlanid, buffer, responselength, 1)) { if (!ac_kmod_send_data(&session->sockaddrdata.ss, wlan->device->radioid, session->binding, buffer, responselength)) {
capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode);
/* Active Station */ /* Active Station */
station->flags |= AC_STATION_FLAGS_ASSOCIATE; station->flags |= AC_STATION_FLAGS_ASSOCIATE;
ac_stations_authorize_station(sessiondata->session, station); ac_stations_authorize_station(session, station);
} else { } else {
capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
} }
} else { } else {
capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext);
ac_stations_delete_station(sessiondata->session, station); ac_stations_delete_station(session, station);
} }
} }
} }
@ -256,7 +256,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
} }
/* */ /* */
static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
struct ac_station* station; struct ac_station* station;
@ -269,7 +269,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
/* Get station */ /* Get station */
if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) {
station = ac_stations_get_station(sessiondata->session, radioid, mgmt->bssid, mgmt->da); station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da);
if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) {
capwap_logging_info("Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode); capwap_logging_info("Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode);
@ -289,7 +289,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
} }
/* Active Station */ /* Active Station */
ac_stations_authorize_station(sessiondata->session, station); ac_stations_authorize_station(session, station);
} }
} }
} }
@ -297,7 +297,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
} }
/* */ /* */
static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
@ -311,7 +311,7 @@ static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_dat
} }
/* */ /* */
static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
@ -325,7 +325,7 @@ static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_da
} }
/* */ /* */
static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
struct ieee80211_ie_items ieitems; struct ieee80211_ie_items ieitems;
@ -339,7 +339,7 @@ static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_data_t* se
} }
/* */ /* */
static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) {
int ielength; int ielength;
const uint8_t* stationaddress; const uint8_t* stationaddress;
struct ac_station* station; struct ac_station* station;
@ -355,19 +355,20 @@ static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_data_t*
stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da); stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da);
/* Delete station */ /* Delete station */
station = ac_stations_get_station(sessiondata->session, radioid, NULL, stationaddress); station = ac_stations_get_station(session, radioid, NULL, stationaddress);
if (station) { if (station) {
station->flags &= ~(AC_STATION_FLAGS_AUTHORIZED | AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); /* Delete station without forward another IEEE802.11 deauthentication message */
ac_stations_delete_station(sessiondata->session, station); station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_stations_delete_station(session, station);
} }
} }
/* */ /* */
static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) { static void ac_ieee80211_mgmt_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) {
switch (framecontrol_subtype) { switch (framecontrol_subtype) {
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) {
ac_ieee80211_mgmt_probe_request_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_probe_request_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -375,7 +376,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) {
ac_ieee80211_mgmt_authentication_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_authentication_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -383,7 +384,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) {
ac_ieee80211_mgmt_association_request_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_association_request_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -391,7 +392,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) {
ac_ieee80211_mgmt_association_response_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_association_response_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -399,7 +400,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) {
ac_ieee80211_mgmt_reassociation_request_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_reassociation_request_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -407,7 +408,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse))) {
ac_ieee80211_mgmt_reassociation_response_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_reassociation_response_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -415,7 +416,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) {
ac_ieee80211_mgmt_disassociation_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_disassociation_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -423,7 +424,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: {
if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) { if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) {
ac_ieee80211_mgmt_deauthentication_packet(sessiondata, radioid, mgmt, mgmtlength); ac_ieee80211_mgmt_deauthentication_packet(session, radioid, mgmt, mgmtlength);
} }
break; break;
@ -436,12 +437,12 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
} }
/* */ /* */
void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header* header, int length) { void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length) {
uint16_t framecontrol; uint16_t framecontrol;
uint16_t framecontrol_type; uint16_t framecontrol_type;
uint16_t framecontrol_subtype; uint16_t framecontrol_subtype;
ASSERT(sessiondata != NULL); ASSERT(session != NULL);
ASSERT(IS_VALID_RADIOID(radioid)); ASSERT(IS_VALID_RADIOID(radioid));
ASSERT(header != NULL); ASSERT(header != NULL);
ASSERT(length >= sizeof(struct ieee80211_header)); ASSERT(length >= sizeof(struct ieee80211_header));
@ -453,6 +454,6 @@ void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid,
/* Parsing frame */ /* Parsing frame */
if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) {
ac_ieee80211_mgmt_packet(sessiondata, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype); ac_ieee80211_mgmt_packet(session, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype);
} }
} }

View File

@ -2,6 +2,7 @@
#include <netlink/genl/genl.h> #include <netlink/genl/genl.h>
#include <netlink/genl/family.h> #include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h> #include <netlink/genl/ctrl.h>
#include "ac_session.h"
#include "nlsmartcapwap.h" #include "nlsmartcapwap.h"
/* Compatibility functions */ /* Compatibility functions */
@ -84,8 +85,37 @@ static int ac_kmod_ack_handler(struct nl_msg* msg, void* arg) {
/* */ /* */
static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) {
switch (gnlh->cmd) { switch (gnlh->cmd) {
default: { case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: {
capwap_logging_debug("*** ac_kmod_event_handler: %d", (int)gnlh->cmd); if (tb_msg[NLSMARTCAPWAP_ATTR_ADDRESS] && tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]) {
struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]));
if (session) {
/* Save data channel address */
if (session->sockaddrdata.ss.ss_family == AF_UNSPEC) {
capwap_lock_enter(&session->sessionlock);
memcpy(&session->sockaddrdata.ss, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
capwap_lock_exit(&session->sessionlock);
}
/* Notify keep-alive */
ac_session_send_action(session, AC_SESSION_ACTION_RECV_KEEPALIVE, 0, NULL, 0);
ac_session_release_reference(session);
}
}
break;
}
case NLSMARTCAPWAP_CMD_RECV_DATA: {
if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID] && tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]));
if (session) {
ac_session_send_action(session, AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET, 0, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]));
ac_session_release_reference(session);
}
}
break; break;
} }
} }
@ -95,10 +125,10 @@ static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg
/* */ /* */
static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) { static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) {
struct nlattr* tb_msg[NLSMARTCAPWAP_AC_ATTR_MAX + 1]; struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1];
struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
nla_parse(tb_msg, NLSMARTCAPWAP_AC_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
return ac_kmod_event_handler(gnlh, tb_msg, data); return ac_kmod_event_handler(gnlh, tb_msg, data);
} }
@ -145,7 +175,7 @@ static int ac_kmod_send_and_recv_msg(struct nl_msg* msg, ac_kmod_valid_cb valid_
} }
/* */ /* */
static int ac_kmod_link(void) { static int ac_kmod_link(uint32_t hash, uint32_t threads) {
int result; int result;
struct nl_msg* msg; struct nl_msg* msg;
@ -156,7 +186,9 @@ static int ac_kmod_link(void) {
} }
/* */ /* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_AC_CMD_LINK, 0); genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD, hash);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT, threads);
/* */ /* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
@ -188,6 +220,67 @@ static void ac_kmod_event_receive(int fd, void** params, int paramscount) {
} }
} }
/* */
int ac_kmod_send_keepalive(struct sockaddr_storage* sockaddr) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to send keep-alive: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_send_data(struct sockaddr_storage* sockaddr, uint8_t radioid, uint8_t binding, const uint8_t* data, int length) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
ASSERT(data != NULL);
ASSERT(length > 0);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, binding);
nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, data);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to send data: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */ /* */
int ac_kmod_isconnected(void) { int ac_kmod_isconnected(void) {
return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0); return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0);
@ -222,7 +315,106 @@ int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count) {
} }
/* */ /* */
int ac_kmod_init(void) { int ac_kmod_createdatachannel(int family, unsigned short port) {
int result;
struct nl_msg* msg;
struct sockaddr_storage sockaddr;
ASSERT((family == AF_INET) || (family == AF_INET6));
ASSERT(port != 0);
/* */
memset(&sockaddr, 0, sizeof(struct sockaddr_storage));
sockaddr.ss_family = family;
if (sockaddr.ss_family == AF_INET) {
((struct sockaddr_in*)&sockaddr)->sin_port = htons(port);
} else if (sockaddr.ss_family == AF_INET6) {
((struct sockaddr_in6*)&sockaddr)->sin6_port = htons(port);
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to bind kernel socket: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint16_t mtu) {
int result;
struct nl_msg* msg;
ASSERT(sessionid != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_NEW_SESSION, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu);
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result) {
capwap_logging_error("Unable to create data session: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_delete_datasession(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid) {
int result;
struct nl_msg* msg;
ASSERT(sessionid != NULL);
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_SESSION, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
if (sockaddr && (sockaddr->ss_family != AF_UNSPEC)) {
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
}
/* */
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
if (result && (result != ENOENT)) {
capwap_logging_error("Unable to delete data session: %d", result);
}
/* */
nlmsg_free(msg);
return result;
}
/* */
int ac_kmod_init(uint32_t hash, uint32_t threads) {
int result; int result;
/* Configure netlink callback */ /* Configure netlink callback */
@ -242,7 +434,7 @@ int ac_kmod_init(void) {
g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl); g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl);
/* Get nlsmartcapwap netlink family */ /* Get nlsmartcapwap netlink family */
g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, SMARTCAPWAP_AC_GENL_NAME); g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME);
if (g_ac.kmodhandle.nlsmartcapwap_id < 0) { if (g_ac.kmodhandle.nlsmartcapwap_id < 0) {
capwap_logging_warning("Unable to found kernel module"); capwap_logging_warning("Unable to found kernel module");
ac_kmod_free(); ac_kmod_free();
@ -254,7 +446,7 @@ int ac_kmod_init(void) {
nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL); nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL);
/* Link to kernel module */ /* Link to kernel module */
result = ac_kmod_link(); result = ac_kmod_link(hash, threads);
if (result) { if (result) {
ac_kmod_free(); ac_kmod_free();
return result; return result;

View File

@ -32,11 +32,22 @@ struct ac_kmod_event {
}; };
/* */ /* */
int ac_kmod_init(void); int ac_kmod_init(uint32_t hash, uint32_t threads);
void ac_kmod_free(void); void ac_kmod_free(void);
/* */ /* */
int ac_kmod_isconnected(void); int ac_kmod_isconnected(void);
int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count); int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count);
/* */
int ac_kmod_createdatachannel(int family, unsigned short port);
/* */
int ac_kmod_send_keepalive(struct sockaddr_storage* sockaddr);
int ac_kmod_send_data(struct sockaddr_storage* sockaddr, uint8_t radioid, uint8_t binding, const uint8_t* data, int length);
/* */
int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint16_t mtu);
int ac_kmod_delete_datasession(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid);
#endif /* __AC_KMOD_HEADER__ */ #endif /* __AC_KMOD_HEADER__ */

View File

@ -6,8 +6,8 @@
#include "ac_backend.h" #include "ac_backend.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#define AC_ERROR_TIMEOUT -1000 #define AC_NO_ERROR -1000
#define AC_ERROR_ACTION_SESSION -1001 #define AC_ERROR_TIMEOUT -1001
/* */ /* */
static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_notify_reset_t* reset) { static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_notify_reset_t* reset) {
@ -39,7 +39,7 @@ static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_no
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send Reset Request to WTP */ /* Send Reset Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0; session->retransmitcount = 0;
ac_dfa_change_state(session, CAPWAP_RESET_STATE); ac_dfa_change_state(session, CAPWAP_RESET_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
@ -49,7 +49,7 @@ static int ac_session_action_resetwtp(struct ac_session_t* session, struct ac_no
ac_session_teardown(session); ac_session_teardown(session);
} }
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
} }
/* */ /* */
@ -62,10 +62,10 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
/* Check if WLAN id is valid and not used */ /* Check if WLAN id is valid and not used */
if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) { if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) {
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
#if 0 #if 0
} else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) { } else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) {
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
#endif #endif
} }
@ -102,7 +102,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send WLAN Configuration Request to WTP */ /* Send WLAN Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0; session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else { } else {
@ -111,7 +111,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
ac_session_teardown(session); ac_session_teardown(session);
} }
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
} }
/* */ /* */
@ -125,7 +125,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
/* Check if RADIO id and WLAN id is valid */ /* Check if RADIO id and WLAN id is valid */
if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) { if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) {
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
} }
/* */ /* */
@ -167,7 +167,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send Station Configuration Request to WTP */ /* Send Station Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0; session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else { } else {
@ -176,7 +176,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
ac_session_teardown(session); ac_session_teardown(session);
} }
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
} }
/* */ /* */
@ -189,7 +189,7 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
/* Check if RADIO id is valid */ /* Check if RADIO id is valid */
if (!IS_VALID_RADIOID(notify->radioid)) { if (!IS_VALID_RADIOID(notify->radioid)) {
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
} }
/* */ /* */
@ -216,7 +216,7 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send Station Configuration Request to WTP */ /* Send Station Configuration Request to WTP */
if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
session->retransmitcount = 0; session->retransmitcount = 0;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else { } else {
@ -225,12 +225,25 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
ac_session_teardown(session); ac_session_teardown(session);
} }
return AC_ERROR_ACTION_SESSION; return AC_NO_ERROR;
}
/* */
static int ac_session_action_recv_ieee80211_mgmt_packet(struct ac_session_t* session, struct capwap_header* header, long length) {
long headersize;
/* Retrieve info */
headersize = GET_HLEN_HEADER(header) * 4;
if ((GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) && ((length - headersize) >= sizeof(struct ieee80211_header))) {
ac_ieee80211_packet(session, GET_RID_HEADER(header), (struct ieee80211_header*)(((char*)header) + headersize), (length - headersize));
}
return AC_NO_ERROR;
} }
/* */ /* */
static int ac_session_action_execute(struct ac_session_t* session, struct ac_session_action* action) { static int ac_session_action_execute(struct ac_session_t* session, struct ac_session_action* action) {
int result = AC_ERROR_ACTION_SESSION; int result = AC_NO_ERROR;
switch (action->action) { switch (action->action) {
case AC_SESSION_ACTION_CLOSE: { case AC_SESSION_ACTION_CLOSE: {
@ -248,24 +261,43 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses
break; break;
} }
case AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA: { case AC_SESSION_ACTION_RECV_KEEPALIVE: {
int valid = 0; #ifdef DEBUG
struct ac_soap_response* response; {
char sessionname[33];
capwap_sessionid_printf(&session->sessionid, sessionname);
capwap_logging_debug("Receive Keep-Alive from %s", sessionname);
}
#endif
/* Send keep-alive response */
ac_kmod_send_keepalive(&session->sockaddrdata.ss);
capwap_timeout_set(session->timeout, session->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
/* Capwap handshake complete, notify event to backend */ /* */
response = ac_soap_runningwtpsession(session, session->wtpid); if (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) {
if (response) { struct ac_soap_response* response;
valid = ((response->responsecode == HTTP_RESULT_OK) ? 1 : 0);
ac_soapclient_free_response(response); /* Capwap handshake complete, notify event to backend */
response = ac_soap_runningwtpsession(session, session->wtpid);
if (response) {
if (response->responsecode == HTTP_RESULT_OK) {
ac_dfa_change_state(session, CAPWAP_RUN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
result = CAPWAP_ERROR_CLOSE;
}
ac_soapclient_free_response(response);
} else {
result = CAPWAP_ERROR_CLOSE;
}
} }
if (valid) { break;
ac_dfa_change_state(session, CAPWAP_RUN_STATE); }
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {
result = CAPWAP_ERROR_CLOSE;
}
case AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET: {
result = ac_session_action_recv_ieee80211_mgmt_packet(session, (struct capwap_header*)action->data, action->length);
break; break;
} }
@ -289,6 +321,18 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses
result = ac_session_action_station_configuration_ieee8011_delete_station(session, (struct ac_notify_station_configuration_ieee8011_delete_station*)action->data); result = ac_session_action_station_configuration_ieee8011_delete_station(session, (struct ac_notify_station_configuration_ieee8011_delete_station*)action->data);
break; break;
} }
case AC_SESSION_ACTION_STATION_ROAMING: {
struct ac_station* station;
/* Delete station */
station = ac_stations_get_station(session, RADIOID_ANY, NULL, (uint8_t*)action->data);
if (station) {
ac_stations_delete_station(session, station);
}
break;
}
} }
return result; return result;
@ -324,8 +368,6 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
} else if (session->packets->count > 0) { } else if (session->packets->count > 0) {
struct capwap_list_item* itempacket; struct capwap_list_item* itempacket;
capwap_logging_debug("Receive control packet");
/* Get packet */ /* Get packet */
itempacket = capwap_itemlist_remove_head(session->packets); itempacket = capwap_itemlist_remove_head(session->packets);
capwap_lock_exit(&session->sessionlock); capwap_lock_exit(&session->sessionlock);
@ -344,7 +386,7 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (session->dtls.action == CAPWAP_DTLS_ACTION_DATA)) { if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (session->dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
if (session->state == CAPWAP_DTLS_CONNECT_STATE) { if (session->state == CAPWAP_DTLS_CONNECT_STATE) {
ac_dfa_change_state(session, CAPWAP_JOIN_STATE); ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} }
} }
} }
@ -420,11 +462,6 @@ static void ac_dfa_execute(struct ac_session_t* session, struct capwap_parsed_pa
break; break;
} }
case CAPWAP_DATA_CHECK_TO_RUN_STATE: {
ac_dfa_state_datacheck_to_run(session, packet);
break;
}
case CAPWAP_RUN_STATE: { case CAPWAP_RUN_STATE: {
ac_dfa_state_run(session, packet); ac_dfa_state_run(session, packet);
break; break;
@ -472,7 +509,7 @@ static void ac_send_invalid_request(struct ac_session_t* session, uint32_t error
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send unknown response */ /* Send unknown response */
capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], responsefragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr); capwap_crypt_sendto_fragmentpacket(&session->dtls, responsefragmentpacket);
/* Don't buffering a packets sent */ /* Don't buffering a packets sent */
capwap_list_free(responsefragmentpacket); capwap_list_free(responsefragmentpacket);
@ -491,12 +528,6 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_logging_debug("Release Session AC %s", sessionname); capwap_logging_debug("Release Session AC %s", sessionname);
#endif #endif
/* Release session data reference */
if (session->sessiondata) {
ac_session_data_close(session->sessiondata);
ac_session_data_release_reference(session->sessiondata);
}
/* Release last reference */ /* Release last reference */
capwap_lock_enter(&session->sessionlock); capwap_lock_enter(&session->sessionlock);
session->count--; session->count--;
@ -523,6 +554,9 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock); capwap_lock_exit(&session->sessionlock);
/* Close data channel */
ac_kmod_delete_datasession(&session->sockaddrdata.ss, &session->sessionid);
/* Free DTSL Control */ /* Free DTSL Control */
capwap_crypt_freesession(&session->dtls); capwap_crypt_freesession(&session->dtls);
@ -563,38 +597,6 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_itemlist_free(session->itemlist); capwap_itemlist_free(session->itemlist);
} }
/* */
static void ac_session_report_connection(struct ac_session_t* session) {
char localip[INET6_ADDRSTRLEN + 10] = "";
char remoteip[INET6_ADDRSTRLEN + 10] = "";
if (session->connection.localaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.localaddr)->sin_port));
} else if (session->connection.localaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.localaddr)->sin6_port));
}
if (session->connection.remoteaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&session->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&session->connection.remoteaddr)->sin_port));
} else if (session->connection.remoteaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&session->connection.remoteaddr)->sin6_port));
}
capwap_logging_info("Start control channel from %s to %s", remoteip, localip);
}
/* */ /* */
static void ac_session_run(struct ac_session_t* session) { static void ac_session_run(struct ac_session_t* session) {
int res; int res;
@ -605,9 +607,6 @@ static void ac_session_run(struct ac_session_t* session) {
ASSERT(session != NULL); ASSERT(session != NULL);
/* */
ac_session_report_connection(session);
/* Configure DFA */ /* Configure DFA */
if (g_ac.enabledtls) { if (g_ac.enabledtls) {
if (!ac_dtls_setup(session)) { if (!ac_dtls_setup(session)) {
@ -616,7 +615,7 @@ static void ac_session_run(struct ac_session_t* session) {
} else { } else {
/* Wait Join request */ /* Wait Join request */
ac_dfa_change_state(session, CAPWAP_JOIN_STATE); ac_dfa_change_state(session, CAPWAP_JOIN_STATE);
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_state_join_timeout, session, NULL); capwap_timeout_set(session->timeout, session->idtimercontrol, AC_JOIN_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} }
while (session->state != CAPWAP_DTLS_TEARDOWN_STATE) { while (session->state != CAPWAP_DTLS_TEARDOWN_STATE) {
@ -628,24 +627,31 @@ static void ac_session_run(struct ac_session_t* session) {
} }
} else if (length > 0) { } else if (length > 0) {
/* Check generic capwap packet */ /* Check generic capwap packet */
check = capwap_sanity_check(1, CAPWAP_UNDEF_STATE, buffer, length, 0, 0); check = capwap_sanity_check(CAPWAP_UNDEF_STATE, buffer, length, 0);
if (check == CAPWAP_PLAIN_PACKET) { if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_parsed_packet packet; struct capwap_parsed_packet packet;
/* Defragment management */ /* Defragment management */
if (!session->rxmngpacket) { if (!session->rxmngpacket) {
session->rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET); session->rxmngpacket = capwap_packet_rxmng_create_message();
} }
/* If request, defragmentation packet */ /* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(session->rxmngpacket, buffer, length); check = capwap_packet_rxmng_add_recv_packet(session->rxmngpacket, buffer, length);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) { if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Receive all fragment */ /* Receive all fragment */
if (!capwap_recv_retrasmitted_request(&session->dtls, session->rxmngpacket, &session->connection, session->lastrecvpackethash, session->responsefragmentpacket)) { if (capwap_is_request_type(session->rxmngpacket->ctrlmsg.type) && (session->remotetype == session->rxmngpacket->ctrlmsg.type) && (session->remoteseqnumber == session->rxmngpacket->ctrlmsg.seq)) {
/* Retransmit response */
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->responsefragmentpacket)) {
capwap_logging_error("Error to resend response packet");
} else {
capwap_logging_debug("Retrasmitted control packet");
}
} else {
/* Check message type */ /* Check message type */
res = capwap_check_message_type(session->rxmngpacket); res = capwap_check_message_type(session->rxmngpacket);
if (res == VALID_MESSAGE_TYPE) { if (res == VALID_MESSAGE_TYPE) {
res = capwap_parsing_packet(session->rxmngpacket, &session->connection, &packet); res = capwap_parsing_packet(session->rxmngpacket, &packet);
if (res == PARSING_COMPLETE) { if (res == PARSING_COMPLETE) {
int hasrequest = capwap_is_request_type(session->rxmngpacket->ctrlmsg.type); int hasrequest = capwap_is_request_type(session->rxmngpacket->ctrlmsg.type);
@ -713,8 +719,6 @@ static void ac_session_run(struct ac_session_t* session) {
ac_send_invalid_request(session, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST); ac_send_invalid_request(session, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
} }
} }
} else {
capwap_logging_debug("Retrasmitted control packet");
} }
/* Free memory */ /* Free memory */
@ -821,9 +825,19 @@ void ac_session_teardown(struct ac_session_t* session) {
} }
} }
/* Remove timer */
if (session->idtimercontrol != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_unset(session->timeout, session->idtimercontrol);
session->idtimercontrol = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
if (session->idtimerkeepalivedead != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_unset(session->timeout, session->idtimerkeepalivedead);
session->idtimerkeepalivedead = CAPWAP_TIMEOUT_INDEX_NO_SET;
}
/* */ /* */
ac_dfa_change_state(session, CAPWAP_DTLS_TEARDOWN_STATE); ac_dfa_change_state(session, CAPWAP_DTLS_TEARDOWN_STATE);
capwap_timeout_unset(session->timeout, session->idtimercontrol);
} }
/* */ /* */
@ -850,53 +864,31 @@ void* ac_session_thread(void* param) {
/* */ /* */
void ac_get_control_information(struct capwap_list* controllist) { void ac_get_control_information(struct capwap_list* controllist) {
struct capwap_list* addrlist; int count;
struct capwap_list_item* item; struct capwap_list_item* item;
ASSERT(controllist != NULL); ASSERT(controllist != NULL);
/* Detect local address */ /* */
addrlist = capwap_list_create(); capwap_rwlock_rdlock(&g_ac.sessionslock);
capwap_interface_list(&g_ac.net, addrlist); count = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* Prepare control list */ /* Prepare control list */
for (item = addrlist->first; item != NULL; item = item->next) { for (item = g_ac.addrlist->first; item != NULL; item = item->next) {
struct capwap_list_item* itemcontrol; struct capwap_list_item* itemcontrol;
struct ac_session_control* sessioncontrol; struct ac_session_control* sessioncontrol;
struct sockaddr_storage* address = (struct sockaddr_storage*)item->item; union sockaddr_capwap* address = (union sockaddr_capwap*)item->item;
/* */ /* */
itemcontrol = capwap_itemlist_create(sizeof(struct ac_session_control)); itemcontrol = capwap_itemlist_create(sizeof(struct ac_session_control));
sessioncontrol = (struct ac_session_control*)itemcontrol->item; sessioncontrol = (struct ac_session_control*)itemcontrol->item;
memcpy(&sessioncontrol->localaddress, address, sizeof(struct sockaddr_storage)); memcpy(&sessioncontrol->localaddress, address, sizeof(union sockaddr_capwap));
sessioncontrol->count = 0; sessioncontrol->count = count;
/* Add */ /* Add */
capwap_itemlist_insert_after(controllist, NULL, itemcontrol); capwap_itemlist_insert_after(controllist, NULL, itemcontrol);
} }
/* Free local address list */
capwap_list_free(addrlist);
/* */
capwap_rwlock_rdlock(&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->connection.localaddr, &sessioncontrol->localaddress)) {
sessioncontrol->count++;
}
}
}
/* */
capwap_rwlock_exit(&g_ac.sessionslock);
} }
/* */ /* */
@ -911,7 +903,8 @@ void ac_free_reference_last_response(struct ac_session_t* session) {
ASSERT(session); ASSERT(session);
capwap_list_flush(session->responsefragmentpacket); capwap_list_flush(session->responsefragmentpacket);
memset(&session->lastrecvpackethash[0], 0, sizeof(session->lastrecvpackethash)); session->remotetype = 0;
session->remoteseqnumber = 0;
} }
/* */ /* */
@ -973,17 +966,20 @@ void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long
struct ac_session_t* session = (struct ac_session_t*)context; struct ac_session_t* session = (struct ac_session_t*)context;
if (!session->requestfragmentpacket->count) { if (!session->requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet");
ac_session_teardown(session); ac_session_teardown(session);
} else { } else {
session->retransmitcount++; session->retransmitcount++;
if (session->retransmitcount >= AC_MAX_RETRANSMIT) { if (session->retransmitcount >= AC_MAX_RETRANSMIT) {
capwap_logging_info("Retransmition request packet timeout");
/* Timeout reset state */ /* Timeout reset state */
ac_free_reference_last_request(session); ac_free_reference_last_request(session);
ac_session_teardown(session); ac_session_teardown(session);
} else { } else {
/* Retransmit Reset Request */ /* Retransmit Request */
capwap_logging_debug("Retransmition request packet"); capwap_logging_debug("Retransmition request packet");
if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->connection.socket.socket[session->connection.socket.type], session->requestfragmentpacket, &session->connection.localaddr, &session->connection.remoteaddr)) { if (!capwap_crypt_sendto_fragmentpacket(&session->dtls, session->requestfragmentpacket)) {
capwap_logging_error("Error to send request packet"); capwap_logging_error("Error to send request packet");
} }
@ -994,5 +990,6 @@ void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long
} }
void ac_dfa_teardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { void ac_dfa_teardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_info("Session timeout, teardown");
ac_session_teardown((struct ac_session_t*)context); ac_session_teardown((struct ac_session_t*)context);
} }

View File

@ -15,23 +15,23 @@ struct ac_packet {
/* */ /* */
struct ac_session_control { struct ac_session_control {
struct sockaddr_storage localaddress; union sockaddr_capwap localaddress;
unsigned short count; unsigned short count;
}; };
/* */ /* */
#define AC_SESSION_ACTION_CLOSE 0 #define AC_SESSION_ACTION_CLOSE 0
#define AC_SESSION_ACTION_RESET_WTP 1 #define AC_SESSION_ACTION_RESET_WTP 1
#define AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA 2 #define AC_SESSION_ACTION_NOTIFY_EVENT 2
#define AC_SESSION_ACTION_NOTIFY_EVENT 3
#define AC_SESSION_ACTION_ADDWLAN 4
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION 5
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION 6
#define AC_SESSION_DATA_ACTION_ROAMING_STATION 1 #define AC_SESSION_ACTION_RECV_KEEPALIVE 10
#define AC_SESSION_DATA_ACTION_ASSIGN_BSSID 2 #define AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET 11
#define AC_SESSION_DATA_ACTION_ADD_STATION_STATUS 3
#define AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS 4 #define AC_SESSION_ACTION_ADDWLAN 20
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION 30
#define AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION 31
#define AC_SESSION_ACTION_STATION_ROAMING 32
/* */ /* */
struct ac_session_action { struct ac_session_action {
@ -94,56 +94,8 @@ struct ac_notify_station_configuration_ieee8011_delete_station {
uint8_t address[MACADDRESS_EUI48_LENGTH]; uint8_t address[MACADDRESS_EUI48_LENGTH];
}; };
/* */
struct ac_notify_add_station_status {
uint8_t radioid;
uint8_t wlanid;
uint8_t address[MACADDRESS_EUI48_LENGTH];
uint16_t statuscode;
};
/* */
struct ac_notify_delete_station_status {
uint8_t radioid;
uint8_t address[MACADDRESS_EUI48_LENGTH];
uint16_t statuscode;
};
/* */ /* */
struct ac_session_t; struct ac_session_t;
struct ac_session_data_t;
/* AC sessions data */
struct ac_session_data_t {
int running;
pthread_t threadid;
struct capwap_list_item* itemlist; /* My itemlist into g_ac.sessionsdata */
/* Reference */
long count;
capwap_event_t changereference;
/* */
int enabledtls;
unsigned short mtu;
unsigned short fragmentid;
struct capwap_connection connection;
struct capwap_dtls dtls;
struct capwap_timeout* timeout;
unsigned long idtimercontrol;
unsigned long idtimerkeepalivedead;
capwap_event_t waitpacket;
capwap_lock_t sessionlock;
struct capwap_list* action;
struct capwap_list* packets;
struct capwap_packet_rxmng* rxmngpacket;
struct ac_session_t* session;
struct capwap_sessionid_element sessionid;
};
/* AC sessions */ /* AC sessions */
struct ac_session_t { struct ac_session_t {
@ -166,17 +118,18 @@ struct ac_session_t {
unsigned long state; unsigned long state;
struct ac_state dfa; struct ac_state dfa;
/* */
unsigned short binding; unsigned short binding;
struct ac_session_data_t* sessiondata;
struct capwap_sessionid_element sessionid; struct capwap_sessionid_element sessionid;
int teardown;
unsigned short mtu; unsigned short mtu;
struct capwap_dtls dtls; struct capwap_dtls dtls;
struct capwap_connection connection;
union sockaddr_capwap sockaddrdata;
struct capwap_timeout* timeout; struct capwap_timeout* timeout;
unsigned long idtimercontrol; unsigned long idtimercontrol;
unsigned long idtimerkeepalivedead;
capwap_event_t waitpacket; capwap_event_t waitpacket;
capwap_lock_t sessionlock; capwap_lock_t sessionlock;
@ -185,14 +138,16 @@ struct ac_session_t {
struct capwap_list* notifyevent; struct capwap_list* notifyevent;
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short fragmentid; unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket; struct capwap_packet_rxmng* rxmngpacket;
uint8_t localseqnumber;
struct capwap_list* requestfragmentpacket; struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount; int retransmitcount;
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
}; };
/* Session */ /* Session */
@ -202,21 +157,13 @@ void ac_session_teardown(struct ac_session_t* session);
void ac_session_close(struct ac_session_t* session); void ac_session_close(struct ac_session_t* session);
void ac_session_release_reference(struct ac_session_t* session); void ac_session_release_reference(struct ac_session_t* session);
/* Session data */ /* */
void* ac_session_data_thread(void* param); struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid);
void ac_session_data_close(struct ac_session_data_t* sessiondata); int ac_has_sessionid(struct capwap_sessionid_element* sessionid);
void ac_session_data_send_action(struct ac_session_data_t* sessiondata, long action, long param, void* data, long length);
void ac_session_data_release_reference(struct ac_session_data_t* sessiondata);
int ac_session_data_send_data_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe);
/* IEEE802.11 Packet */
void ac_ieee80211_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, const struct ieee80211_header* header, int length);
/* */ /* */
int ac_has_sessionid(struct capwap_sessionid_element* sessionid);
int ac_has_wtpid(const char* wtpid);
struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid); struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid);
int ac_has_wtpid(const char* wtpid);
/* */ /* */
char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata); char* ac_get_printable_wtpid(struct capwap_wtpboarddata_element* wtpboarddata);
@ -231,6 +178,9 @@ 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_request(struct ac_session_t* session);
void ac_free_reference_last_response(struct ac_session_t* session); void ac_free_reference_last_response(struct ac_session_t* session);
/* */
void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length);
/* */ /* */
int ac_msgqueue_init(void); int ac_msgqueue_init(void);
void ac_msgqueue_free(void); void ac_msgqueue_free(void);
@ -238,8 +188,6 @@ void ac_msgqueue_notify_closethread(pthread_t threadid);
/* */ /* */
int ac_dtls_setup(struct ac_session_t* session); int ac_dtls_setup(struct ac_session_t* session);
int ac_dtls_data_setup(struct ac_session_data_t* sessiondata);
void ac_dtls_setup_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
/* */ /* */
void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); void ac_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
@ -248,20 +196,11 @@ void ac_dfa_teardown_timeout(struct capwap_timeout* timeout, unsigned long index
/* */ /* */
void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_postjoin(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_join_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_configure(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_imagedata(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_imagedata(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck_to_run(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_datacheck_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param);
void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_run(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_reset(struct ac_session_t* session, struct capwap_parsed_packet* packet); void ac_dfa_state_reset(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_teardown(struct ac_session_t* session); void ac_dfa_state_teardown(struct ac_session_t* session);
/* Soap function */ /* Soap function */

View File

@ -1,527 +0,0 @@
#include "ac.h"
#include "capwap_dfa.h"
#include "ac_session.h"
#include "ac_wlans.h"
#include "ieee80211.h"
#include <arpa/inet.h>
#define AC_ERROR_TIMEOUT -1000
#define AC_ERROR_ACTION_SESSION -1001
#define AC_BODY_PACKET_MAX_SIZE 8192
/* */
static int ac_session_data_action_add_station_status(struct ac_session_data_t* sessiondata, struct ac_notify_add_station_status* notify) {
struct ac_wlan* wlan;
struct ac_station* station;
wlan = ac_wlans_get_bssid_with_wlanid(sessiondata->session, notify->radioid, notify->wlanid);
if (wlan) {
station = ac_stations_get_station(sessiondata->session, notify->radioid, wlan->address, notify->address);
if (station) {
if (CAPWAP_RESULTCODE_OK(notify->statuscode)) {
capwap_logging_info("Authorized station: %s", station->addrtext);
/* */
station->flags |= AC_STATION_FLAGS_AUTHORIZED;
capwap_timeout_deletetimer(sessiondata->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} else {
ac_stations_delete_station(sessiondata->session, station);
}
}
}
return AC_ERROR_ACTION_SESSION;
}
/* */
static int ac_session_data_action_delete_station_status(struct ac_session_data_t* sessiondata, struct ac_notify_delete_station_status* notify) {
struct ac_station* station;
station = ac_stations_get_station(sessiondata->session, notify->radioid, NULL, notify->address);
if (station) {
capwap_logging_info("Deauthorized station: %s with %d result code", station->addrtext, (int)notify->statuscode);
/* */
ac_stations_delete_station(sessiondata->session, station);
}
return AC_ERROR_ACTION_SESSION;
}
/* */
static int ac_session_data_action_execute(struct ac_session_data_t* sessiondata, struct ac_session_action* action) {
int result = AC_ERROR_ACTION_SESSION;
switch (action->action) {
case AC_SESSION_DATA_ACTION_ROAMING_STATION: {
struct ac_station* station;
/* Delete station */
station = ac_stations_get_station(sessiondata->session, RADIOID_ANY, NULL, (uint8_t*)action->data);
if (station) {
ac_stations_delete_station(sessiondata->session, station);
}
break;
}
case AC_SESSION_DATA_ACTION_ASSIGN_BSSID: {
ac_wlans_assign_bssid(sessiondata->session, *(struct ac_wlan**)action->data);
break;
}
case AC_SESSION_DATA_ACTION_ADD_STATION_STATUS: {
result = ac_session_data_action_add_station_status(sessiondata, (struct ac_notify_add_station_status*)action->data);
break;
}
case AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS: {
result = ac_session_data_action_delete_station_status(sessiondata, (struct ac_notify_delete_station_status*)action->data);
break;
}
}
return result;
}
/* */
static int ac_network_read(struct ac_session_data_t* sessiondata, void* buffer, int length) {
long waittimeout;
int result = CAPWAP_ERROR_AGAIN;
ASSERT(sessiondata != NULL);
ASSERT(buffer != NULL);
ASSERT(length > 0);
for (;;) {
capwap_lock_enter(&sessiondata->sessionlock);
if (!sessiondata->running) {
capwap_lock_exit(&sessiondata->sessionlock);
return CAPWAP_ERROR_CLOSE;
} else if (sessiondata->action->count > 0) {
struct capwap_list_item* itemaction;
itemaction = capwap_itemlist_remove_head(sessiondata->action);
capwap_lock_exit(&sessiondata->sessionlock);
/* */
result = ac_session_data_action_execute(sessiondata, (struct ac_session_action*)itemaction->item);
/* Free packet */
capwap_itemlist_free(itemaction);
return result;
} else if (sessiondata->packets->count > 0) {
struct capwap_list_item* itempacket;
capwap_logging_debug("Receive data packet");
/* Get packet */
itempacket = capwap_itemlist_remove_head(sessiondata->packets);
capwap_lock_exit(&sessiondata->sessionlock);
if (itempacket) {
struct ac_packet* packet = (struct ac_packet*)itempacket->item;
long packetlength = itempacket->itemsize - sizeof(struct ac_packet);
if (!packet->plainbuffer && sessiondata->dtls.enable) {
int oldaction = sessiondata->dtls.action;
result = capwap_decrypt_packet(&sessiondata->dtls, packet->buffer, packetlength, buffer, length);
if (result == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (sessiondata->dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
capwap_timeout_unset(sessiondata->timeout, sessiondata->idtimercontrol);
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
}
}
} else {
if (packetlength <= length) {
memcpy(buffer, packet->buffer, packetlength);
result = packetlength;
}
}
/* Free packet */
capwap_itemlist_free(itempacket);
}
return result;
}
capwap_lock_exit(&sessiondata->sessionlock);
/* Get timeout */
waittimeout = capwap_timeout_getcoming(sessiondata->timeout);
if (!waittimeout) {
capwap_timeout_hasexpired(sessiondata->timeout);
return AC_ERROR_TIMEOUT;
}
/* Wait packet */
capwap_event_wait_timeout(&sessiondata->waitpacket, waittimeout);
}
return result;
}
/* Management keep-alive */
static int ac_session_data_keepalive(struct ac_session_data_t* sessiondata, struct capwap_parsed_packet* packet) {
int result = 0;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
struct capwap_sessionid_element* sessionid;
/* Get session id */
sessionid = (struct capwap_sessionid_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID);
if (!sessionid) {
return 0;
}
/* */
if (sessiondata->session) {
if (memcmp(sessionid, &sessiondata->sessionid, sizeof(struct capwap_sessionid_element))) {
return 0; /* Invalid session id */
}
} else {
struct capwap_list_item* search;
/* Retrieve session and interconnect with session data */
capwap_rwlock_rdlock(&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))) {
/* Link session and session data */
capwap_lock_enter(&session->sessionlock);
session->count++;
sessiondata->session = session;
capwap_event_signal(&session->changereference);
capwap_lock_exit(&session->sessionlock);
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count++;
session->sessiondata = sessiondata;
capwap_event_signal(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
break;
}
search = search->next;
}
capwap_rwlock_exit(&g_ac.sessionslock);
/* */
if (sessiondata->session) {
#ifdef DEBUG
char sessionname[33];
capwap_sessionid_printf(sessionid, sessionname);
capwap_logging_debug("Establiched Session Data AC %s", sessionname);
#endif
/* Notify established session data */
memcpy(&sessiondata->sessionid, sessionid, sizeof(struct capwap_sessionid_element));
ac_session_send_action(sessiondata->session, AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA, 0, NULL, 0);
} else {
return 0; /* Session not found */
}
}
/* Send keep-alive response */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, GET_WBID_HEADER(packet->rxmngpacket->header));
capwap_header_set_keepalive_flag(&capwapheader, 1);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, sessiondata->mtu);
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &sessiondata->sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, sessiondata->fragmentid);
if (txfragpacket->count == 1) {
/* Send Data keepalive to WTP */
if (capwap_crypt_sendto_fragmentpacket(&sessiondata->dtls, sessiondata->connection.socket.socket[sessiondata->connection.socket.type], txfragpacket, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr)) {
result = 1;
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet");
}
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet");
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}
/* Release reference of session data */
static void ac_session_data_destroy(struct ac_session_data_t* sessiondata) {
#ifdef DEBUG
char sessionname[33];
#endif
ASSERT(sessiondata != NULL);
#ifdef DEBUG
capwap_sessionid_printf(&sessiondata->sessionid, sessionname);
capwap_logging_debug("Release Session Data AC %s", sessionname);
#endif
/* Remove session data from list */
capwap_rwlock_wrlock(&g_ac.sessionslock);
capwap_itemlist_remove(g_ac.sessionsdata, sessiondata->itemlist);
capwap_rwlock_exit(&g_ac.sessionslock);
/* Release session reference */
if (sessiondata->session) {
ac_session_close(sessiondata->session);
ac_session_release_reference(sessiondata->session);
}
/* Release last reference */
capwap_lock_enter(&sessiondata->sessionlock);
sessiondata->count--;
/* Check if all reference is release */
while (sessiondata->count > 0) {
#ifdef DEBUG
capwap_logging_debug("Wait for release Session Data AC %s (count=%d)", sessionname, sessiondata->count);
#endif
/* */
capwap_event_reset(&sessiondata->changereference);
capwap_lock_exit(&sessiondata->sessionlock);
/* Wait */
capwap_event_wait(&sessiondata->changereference);
capwap_lock_enter(&sessiondata->sessionlock);
}
capwap_lock_exit(&sessiondata->sessionlock);
/* Free DTLS */
capwap_crypt_freesession(&sessiondata->dtls);
/* Free resource */
while (sessiondata->packets->count > 0) {
capwap_itemlist_free(capwap_itemlist_remove_head(sessiondata->packets));
}
/* */
capwap_event_destroy(&sessiondata->changereference);
capwap_event_destroy(&sessiondata->waitpacket);
capwap_lock_destroy(&sessiondata->sessionlock);
capwap_list_free(sessiondata->action);
capwap_list_free(sessiondata->packets);
capwap_timeout_free(sessiondata->timeout);
/* Free fragments packet */
if (sessiondata->rxmngpacket) {
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
}
/* Free item */
capwap_itemlist_free(sessiondata->itemlist);
}
/* */
static void ac_session_data_report_connection(struct ac_session_data_t* sessiondata) {
char localip[INET6_ADDRSTRLEN + 10] = "";
char remoteip[INET6_ADDRSTRLEN + 10] = "";
if (sessiondata->connection.localaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.localaddr)->sin_port));
} else if (sessiondata->connection.localaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(localip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.localaddr)->sin6_port));
}
if (sessiondata->connection.remoteaddr.ss_family == AF_INET) {
char buffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, (void*)&((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_addr, buffer, INET_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in*)&sessiondata->connection.remoteaddr)->sin_port));
} else if (sessiondata->connection.remoteaddr.ss_family == AF_INET6) {
char buffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, (void*)&((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_addr, buffer, INET6_ADDRSTRLEN);
sprintf(remoteip, "%s:%hu", buffer, ntohs(((struct sockaddr_in6*)&sessiondata->connection.remoteaddr)->sin6_port));
}
capwap_logging_info("Start data channel from %s to %s", remoteip, localip);
}
/* */
static void ac_session_data_run(struct ac_session_data_t* sessiondata) {
int res;
int check;
int length;
struct capwap_connection connection;
char buffer[CAPWAP_MAX_PACKET_SIZE];
uint8_t radioid;
unsigned short binding;
int bodypacketlength;
uint8_t bodypacket[AC_BODY_PACKET_MAX_SIZE];
ASSERT(sessiondata != NULL);
/* */
ac_session_data_report_connection(sessiondata);
/* Create DTLS channel */
if (sessiondata->enabledtls) {
if (ac_dtls_data_setup(sessiondata)) {
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimercontrol, AC_DTLS_INTERVAL, NULL, NULL, NULL);
} else {
capwap_logging_debug("Unable to start DTLS data");
sessiondata->running = 0;
}
} else {
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
}
/* */
while (sessiondata->running) {
/* Get packet */
length = ac_network_read(sessiondata, buffer, sizeof(buffer));
if (length < 0) {
if ((length == CAPWAP_ERROR_SHUTDOWN) || (length == CAPWAP_ERROR_CLOSE)) {
break; /* Close Session Data */
}
} else if (length > 0) {
/* Check generic capwap packet */
check = capwap_sanity_check(0, CAPWAP_UNDEF_STATE, buffer, length, 0, 0);
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_parsed_packet packet;
/* Defragment management */
if (!sessiondata->rxmngpacket) {
sessiondata->rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_DATA_PACKET);
}
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(sessiondata->rxmngpacket, buffer, length);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Validate message */
if (capwap_check_message_type(sessiondata->rxmngpacket) == VALID_MESSAGE_TYPE) {
/* Parsing packet */
res = capwap_parsing_packet(sessiondata->rxmngpacket, &connection, &packet);
if (res == PARSING_COMPLETE) {
/* Validate packet */
if (!capwap_validate_parsed_packet(&packet, NULL)) {
if (IS_FLAG_K_HEADER(packet.rxmngpacket->header)) {
ac_session_data_keepalive(sessiondata, &packet);
/* Update timeout */
capwap_timeout_set(sessiondata->timeout, sessiondata->idtimerkeepalivedead, AC_MAX_DATA_KEEPALIVE_INTERVAL, NULL, NULL, NULL);
} else {
bodypacketlength = capwap_packet_getdata(sessiondata->rxmngpacket, bodypacket, AC_BODY_PACKET_MAX_SIZE);
/* Parsing body packet */
if (bodypacketlength > 0) {
radioid = GET_RID_HEADER(sessiondata->rxmngpacket->header);
binding = GET_WBID_HEADER(sessiondata->rxmngpacket->header);
if ((binding == CAPWAP_WIRELESS_BINDING_IEEE80211) && (bodypacketlength >= sizeof(struct ieee80211_header))) {
ac_ieee80211_packet(sessiondata, radioid, (struct ieee80211_header*)bodypacket, bodypacketlength);
}
}
}
} else {
capwap_logging_debug("Failed validation parsed data packet");
}
} else {
capwap_logging_debug("Failed parsing data packet");
}
}
/* Free memory */
capwap_free_parsed_packet(&packet);
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
sessiondata->rxmngpacket = NULL;
} else if (check != CAPWAP_REQUEST_MORE_FRAGMENT) {
/* Discard fragments */
capwap_packet_rxmng_free(sessiondata->rxmngpacket);
sessiondata->rxmngpacket = NULL;
}
}
}
}
/* Release reference session data */
ac_session_data_destroy(sessiondata);
}
/* */
void* ac_session_data_thread(void* param) {
pthread_t threadid;
struct ac_session_data_t* sessiondata = (struct ac_session_data_t*)param;
ASSERT(param != NULL);
threadid = sessiondata->threadid;
/* */
capwap_logging_debug("Session data start");
ac_session_data_run(sessiondata);
capwap_logging_debug("Session data end");
/* Notify terminate thread */
ac_msgqueue_notify_closethread(threadid);
/* Thread exit */
pthread_exit(NULL);
return NULL;
}
/* */
int ac_session_data_send_data_packet(struct ac_session_data_t* sessiondata, uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe) {
int result = 0;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
capwap_header_init(&capwapheader, radioid, sessiondata->session->binding);
capwap_header_set_nativeframe_flag(&capwapheader, (leavenativeframe ? 1: 0));
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, sessiondata->mtu);
/* */
if (leavenativeframe) {
capwap_packet_txmng_add_data(txmngpacket, data, length);
} else {
/* TODO */
}
/* Data message complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, sessiondata->fragmentid);
if (txfragpacket->count > 1) {
sessiondata->fragmentid++;
}
/* */
if (!capwap_crypt_sendto_fragmentpacket(&sessiondata->dtls, sessiondata->connection.socket.socket[sessiondata->connection.socket.type], txfragpacket, &sessiondata->connection.localaddr, &sessiondata->connection.remoteaddr)) {
capwap_logging_debug("Warning: error to send data packet");
result = -1;
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}

View File

@ -567,7 +567,7 @@ struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_reques
httprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_TIMEOUT; httprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_TIMEOUT;
/* Create socket */ /* Create socket */
httprequest->sock = socket(httprequest->server->address.ss_family, SOCK_STREAM, 0); httprequest->sock = socket(httprequest->server->address.ss.ss_family, SOCK_STREAM, 0);
if (httprequest->sock < 0) { if (httprequest->sock < 0) {
ac_soapclient_close_request(httprequest, 0); ac_soapclient_close_request(httprequest, 0);
return NULL; return NULL;

View File

@ -21,7 +21,7 @@
/* */ /* */
struct ac_http_soap_server { struct ac_http_soap_server {
int protocol; int protocol;
struct sockaddr_storage address; union sockaddr_capwap address;
char* host; char* host;
char* path; char* path;

View File

@ -42,7 +42,7 @@ static void ac_stations_reset_station(struct ac_session_t* session, struct ac_st
/* Remove timers */ /* Remove timers */
if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) {
capwap_timeout_deletetimer(session->sessiondata->timeout, station->idtimeout); capwap_timeout_deletetimer(session->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} }
@ -153,7 +153,6 @@ int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) {
/* */ /* */
wlan->session = session; wlan->session = session;
wlan->sessiondata = session->sessiondata;
/* Create WLAN list */ /* Create WLAN list */
if (!session->wlans->devices[wlan->device->radioid - 1].wlans) { if (!session->wlans->devices[wlan->device->radioid - 1].wlans) {
@ -354,7 +353,7 @@ struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint
if (ownersession != session) { if (ownersession != session) {
/* Release station from old owner */ /* Release station from old owner */
if (ownersession) { if (ownersession) {
ac_session_data_send_action(ownersession->sessiondata, AC_SESSION_DATA_ACTION_ROAMING_STATION, 0, (void*)address, MACADDRESS_EUI48_LENGTH); ac_session_send_action(ownersession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH);
} }
/* Set station into Global Cache Stations List */ /* Set station into Global Cache Stations List */
@ -411,7 +410,7 @@ void ac_stations_authorize_station(struct ac_session_t* session, struct ac_stati
ASSERT(session->wlans != NULL); ASSERT(session->wlans != NULL);
ASSERT(station != NULL); ASSERT(station != NULL);
/* Active Station only if Authenticated, Associated and not Authrizated */ /* Active Station only if Authenticated, Associated and not Authorizated */
if ((station->flags & AC_STATION_FLAGS_AUTHENTICATED) && (station->flags & AC_STATION_FLAGS_ASSOCIATE) && !(station->flags & AC_STATION_FLAGS_AUTHORIZED)) { if ((station->flags & AC_STATION_FLAGS_AUTHENTICATED) && (station->flags & AC_STATION_FLAGS_ASSOCIATE) && !(station->flags & AC_STATION_FLAGS_AUTHORIZED)) {
memset(&notify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station)); memset(&notify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station));
notify.radioid = station->wlan->device->radioid; notify.radioid = station->wlan->device->radioid;
@ -457,7 +456,7 @@ void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_sta
responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params); responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params);
if (responselength > 0) { if (responselength > 0) {
station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_session_data_send_data_packet(session->sessiondata, station->wlan->device->radioid, station->wlan->wlanid, buffer, responselength, 1); ac_kmod_send_data(&session->sockaddrdata.ss, station->wlan->device->radioid, session->binding, buffer, responselength);
} }
} }
} }

View File

@ -20,7 +20,6 @@ struct ac_wlan {
/* CAPWAP Session */ /* CAPWAP Session */
struct ac_session_t* session; struct ac_session_t* session;
struct ac_session_data_t* sessiondata;
uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE]; uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE];

View File

@ -4,7 +4,10 @@ obj-m += smartcapwap.o
smartcapwap-y := \ smartcapwap-y := \
main.o \ main.o \
netlinkapp.o netlinkapp.o \
capwap.o \
capwap_private.o \
socket.o
all: all:
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules

621
src/ac/kmod/capwap.c Normal file
View File

@ -0,0 +1,621 @@
#include "config.h"
#include <linux/module.h>
#include <linux/ieee80211.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
#define TIMEOUT_PACKET 10
/* */
union capwap_addr sc_localaddr;
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
TRACEKMOD("### sc_capwap_fragment_free\n");
/* */
list_del(&fragment->lru_list);
fragment->flags = 0;
/* Free socket buffer */
while (fragment->fragments) {
struct sk_buff* next = fragment->fragments->next;
kfree_skb(fragment->fragments);
fragment->fragments = next;
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
unsigned long flags;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_defrag_evictor\n");
/* */
if (now.tv64 == 0) {
TRACEKMOD("*** Get time\n");
now = ktime_get();
}
/* Remove last old fragment */
if (!list_empty(&session->fragments.lru_list)) {
spin_lock_irqsave(&session->fragments.lock, flags);
fragment = list_first_entry(&session->fragments.lru_list, struct sc_capwap_fragment, lru_list);
if (fragment) {
delta = ktime_sub(now, fragment->tstamp);
if ((delta.tv64 < 0) || (delta.tv64 > NSEC_PER_SEC)) {
TRACEKMOD("*** Expired fragment %hu\n", fragment->fragmentid);
/* Reset fragment */
sc_capwap_fragment_free(fragment);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
}
}
/* */
static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) {
int len;
int offset;
struct sk_buff* skb;
struct sk_buff* skbfrag;
struct sc_capwap_header* header;
/* */
skbfrag = fragment->fragments;
len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
/* Create new packet */
skb = alloc_skb(len + fragment->totallength, GFP_KERNEL);
if (!skb) {
return NULL;
}
/* The first capwap header is header of reassembled packet without fragment field */
header = (struct sc_capwap_header*)skb_put(skb, len);
memcpy(header, skb->data, len);
SET_FLAG_F_HEADER(header, 0);
SET_FLAG_L_HEADER(header, 0);
header->frag_id = (__be16)0;
header->frag_off = (__be16)0;
/* Copy body */
while (skbfrag) {
offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
len = skb->len - offset;
/* */
memcpy(skb_put(skb, len), skb->data + offset, len);
skbfrag = skbfrag->next;
}
return skb;
}
/* */
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
unsigned long flags;
uint16_t headersize;
uint16_t frag_id;
struct sk_buff* prev;
struct sk_buff* next;
struct sc_capwap_fragment* fragment;
struct sc_skb_capwap_cb* cb;
struct sk_buff* skb_defrag = NULL;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_defrag\n");
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if (skb->len < headersize) {
goto error;
}
/* */
frag_id = be16_to_cpu(header->frag_id);
/* */
cb = CAPWAP_SKB_CB(skb);
cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT;
cb->frag_offset = be16_to_cpu(header->frag_off);
cb->frag_length = skb->len - headersize;
/* */
spin_lock_irqsave(&session->fragments.lock, flags);
/* Get fragment */
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) {
goto error2; /* Queue fragment busy*/
}
/* Init fragment */
if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) {
fragment->flags = CAPWAP_FRAGMENT_ENABLE;
fragment->fragmentid = frag_id;
fragment->fragments = NULL;
fragment->lastfragment = NULL;
fragment->recvlength = 0;
fragment->totallength = 0;
list_add_tail(&fragment->lru_list, &session->fragments.lru_list);
}
/* Search fragment position */
prev = fragment->lastfragment;
if (!prev) {
next = NULL;
} else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) {
if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) < cb->frag_offset) {
next = NULL;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
} else {
prev = NULL;
for (next = fragment->fragments; next != NULL; next = next->next) {
struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next);
if (next_cb->frag_offset < cb->frag_offset) {
if ((next_cb->frag_offset + next_cb->frag_length) < cb->frag_offset) {
break;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
}
prev = next;
}
}
/* Insert fragment */
skb->prev = NULL;
skb->next = next;
if (!next) {
fragment->lastfragment = skb;
}
if (prev) {
prev->next = skb;
} else {
fragment->fragments = skb;
}
/* Update size */
fragment->recvlength += cb->frag_length;
if (IS_FLAG_L_HEADER(header)) {
fragment->totallength = cb->frag_offset + cb->frag_length;
fragment->flags |= CAPWAP_FRAGMENT_LAST;
}
/* Check if receive all fragment */
if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) {
skb_defrag = sc_capwap_reasm(fragment);
/* Free fragment complete */
sc_capwap_fragment_free(fragment);
} else {
/* Update timeout */
fragment->tstamp = skb->tstamp;
if (fragment->tstamp.tv64 == 0) {
fragment->tstamp = ktime_get();
}
/* Set LRU timeout */
if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) {
list_move_tail(&fragment->lru_list, &session->fragments.lru_list);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
return skb_defrag;
error2:
spin_unlock_irqrestore(&session->fragments.lock, flags);
error:
kfree_skb(skb);
return NULL;
}
/* */
int sc_capwap_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_capwap_bind\n");
/* */
ret = sc_socket_bind(sockaddr);
if (ret) {
return ret;
}
memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr));
return 0;
}
/* */
void sc_capwap_initsession(struct sc_capwap_session* session) {
TRACEKMOD("### sc_capwap_initsession\n");
INIT_LIST_HEAD(&session->list);
spin_lock_init(&session->fragmentid_lock);
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
}
/* */
void sc_capwap_freesession(struct sc_capwap_session* session) {
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
}
/* */
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
uint16_t fragmentid;
unsigned long flags;
TRACEKMOD("### sc_capwap_newfragmentid\n");
spin_lock_irqsave(&session->fragmentid_lock, flags);
fragmentid = session->fragmentid++;
spin_unlock_irqrestore(&session->fragmentid_lock, flags);
return fragmentid;
}
/* */
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) {
int length;
struct sc_capwap_header* header;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* msgelement;
TRACEKMOD("### sc_capwap_createkeepalive\n");
/* */
if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) {
return -ENOMEM;
}
/* Preamble CAPWAP header */
header = (struct sc_capwap_header*)buffer;
length = sizeof(struct sc_capwap_header);
buffer += sizeof(struct sc_capwap_header);
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4);
SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211);
SET_FLAG_K_HEADER(header, 1);
/* CAPWAP Data header */
dataheader = (struct sc_capwap_data_message*)buffer;
length += sizeof(struct sc_capwap_data_message);
buffer += sizeof(struct sc_capwap_data_message);
dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element));
/* CAPWAP Keep-Alive Message Element */
msgelement = (struct sc_capwap_message_element*)buffer;
length += sizeof(struct sc_capwap_message_element);
buffer += sizeof(struct sc_capwap_message_element);
msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID);
msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element));
/* Session ID */
memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element));
length += sizeof(struct sc_capwap_sessionid_element);
return length;
}
/* */
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) {
int length;
uint16_t headersize;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* message;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_parsingpacket\n");
/* Linearize socket buffer */
if (skb_linearize(skb)) {
TRACEKMOD("*** Unable to linearize packet\n");
return -EINVAL;
}
/* Check header */
if (skb->len < sizeof(struct sc_capwap_header)) {
TRACEKMOD("*** Invalid capwap header length\n");
return -EINVAL;
} else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) {
TRACEKMOD("*** Invalid capwap header version\n");
return -EINVAL;
} else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) {
TRACEKMOD("*** Packet is encrypted\n");
return -EINVAL; /* Accept only plain packet */
}
/* Cleaning old fragments */
if (session) {
sc_capwap_defrag_evictor(session, skb->tstamp);
}
/* */
if (IS_FLAG_K_HEADER(header)) {
/* Keep alive can not fragment */
if (IS_FLAG_F_HEADER(header)) {
TRACEKMOD("*** Keep alive can not fragment\n");
return -EINVAL;
}
/* */
length = skb->len;
headersize = GET_HLEN_HEADER(header) * 4;
if (length < (headersize + sizeof(struct sc_capwap_data_message))) {
TRACEKMOD("*** Invalid capwap data header length\n");
return -EINVAL;
}
/* Data message */
length -= headersize;
dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize);
headersize = ntohs(dataheader->length);
if (length < headersize) {
TRACEKMOD("*** Capwap data header length mismatch\n");
return -EINVAL;
}
/* Message elements */
headersize -= sizeof(struct sc_capwap_data_message);
message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message));
while (headersize > 0) {
uint16_t msglength = ntohs(message->length);
if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) {
TRACEKMOD("*** Invalid capwap message element length\n");
return -EINVAL;
}
/* */
if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) {
struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element));
if (!session) {
session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid);
if (!session) {
TRACEKMOD("*** Receive unknown keep alive without valid session\n");
return -EINVAL;
}
} else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
TRACEKMOD("*** Session id mismatch\n");
return -EINVAL;
}
/* Session found */
sc_netlink_notify_recv_keepalive(sockaddr, sessionid);
/* Parsing complete */
kfree_skb(skb);
return 0;
}
/* Next message element */
msglength += sizeof(struct sc_capwap_message_element);
message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength);
headersize -= msglength;
}
} else if (session) {
if (IS_FLAG_F_HEADER(header)) {
skb = sc_capwap_defrag(session, skb);
if (!skb) {
return 0;
}
/* Get new header info */
header = (struct sc_capwap_header*)skb->data;
}
/* Parsing data/management packet */
if (!IS_FLAG_T_HEADER(header)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4);
if (ieee80211_is_data_present(hdr->frame_control)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) {
sc_capwap_parsingmgmtpacket(session, skb);
}
}
/* Parsing complete */
kfree_skb(skb);
return 0;
}
return -EINVAL;
}
/* */
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) {
int size;
int length;
int reserve;
int headroom;
int requestfragment;
__be16 fragmentid = 0;
int fragmentoffset = 0;
struct sc_capwap_header* header;
struct sk_buff* clone = NULL;
int packetlength = skb->len;
TRACEKMOD("### sc_capwap_forwarddata\n");
/* Check headroom */
headroom = skb_headroom(skb);
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
printk("*** Expand socket buffer\n");
clone = skb_copy_expand(skb, max_t(int, headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
if (!clone) {
printk("*** Unable to expand socket buffer\n");
return -ENOMEM;
}
skb = clone;
}
/* Check MTU */
requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0);
if (requestfragment) {
fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session));
}
/* */
header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength);
while (packetlength > 0) {
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_WBID_HEADER(header, binding);
SET_RID_HEADER(header, radioid);
SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1));
if (!fragmentoffset) {
uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header);
if (radioaddr) {
SET_FLAG_M_HEADER(header, 1);
memcpy(headeroption, radioaddr, radioaddrlength);
headeroption += radioaddrlength;
}
if (winfo) {
SET_FLAG_W_HEADER(header, 1);
memcpy(headeroption, winfo, winfolength);
headeroption += winfolength;
}
size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
SET_HLEN_HEADER(header, size / 4);
} else {
size = sizeof(struct sc_capwap_header);
SET_HLEN_HEADER(header, size / 4);
}
/* Calculate body size */
length = session->mtu - size;
if (packetlength <= length) {
length = packetlength;
} else if (requestfragment) {
length -= length % 8; /* Capwap fragment size is module 8 */
} else {
break;
}
/* Fragment options */
if (requestfragment) {
SET_FLAG_F_HEADER(header, 1);
if (packetlength == length) {
SET_FLAG_L_HEADER(header, 1);
}
header->frag_id = fragmentid;
header->frag_off = cpu_to_be16(fragmentoffset);
}
/* Send packet */
if (sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr) < 0) {
break;
}
/* */
header = (struct sc_capwap_header*)((uint8_t*)header + (size + length));
fragmentoffset += length;
packetlength -= length;
}
if (clone) {
kfree_skb(clone);
}
return (!packetlength ? 0 : -EIO);
}
/* */
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) {
int i;
char* pos = string;
for (i = 0; i < 16; i++) {
snprintf(pos, 3, "%02x", sessionid->id[i]);
pos += 2;
}
*pos = 0;
}
/* */
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) {
struct sc_capwap_radio_addr* radioaddr;
struct sc_capwap_macaddress_eui48* addr;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
radioaddr = (struct sc_capwap_radio_addr*)buffer;
radioaddr->length = MACADDRESS_EUI48_LENGTH;
addr = (struct sc_capwap_macaddress_eui48*)(buffer + sizeof(struct sc_capwap_radio_addr));
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
return radioaddr;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) {
struct sc_capwap_wireless_information* winfo;
struct sc_capwap_ieee80211_frame_info* frameinfo;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
winfo = (struct sc_capwap_wireless_information*)buffer;
winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info);
frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information));
frameinfo->rssi = rssi;
frameinfo->snr = snr;
frameinfo->rate = cpu_to_be16(rate);
return winfo;
}

128
src/ac/kmod/capwap.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
#define MAX_MTU 9000
#define DEFAULT_MTU 1450
#define MIN_MTU 500
#define IEEE80211_MTU 7981
/* */
#define CAPWAP_FRAGMENT_QUEUE 16
/* */
#define CAPWAP_FRAGMENT_ENABLE 0x0001
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
#define CAPWAP_FRAGMENT_LAST 0x0004
/* */
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0004
#define SKB_CAPWAP_FLAG_PEERADDRESS 0x0010
#define SKB_CAPWAP_FLAG_RADIOID 0x0020
#define SKB_CAPWAP_FLAG_BINDING 0x0040
#define SKB_CAPWAP_FLAG_RADIOADDRESS 0x0080
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0100
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
struct sc_skb_capwap_cb {
uint16_t flags;
struct capwap_addr_little peeraddr;
/* Capwap information */
uint8_t radioid;
uint8_t binding;
/* Radio Address */
uint8_t radioaddr_addr[MACADDRESS_EUI48_LENGTH];
/* Wireless Information */
uint8_t winfo_rssi;
uint8_t winfo_snr;
uint16_t winfo_rate;
/* Fragment */
uint16_t frag_offset;
uint16_t frag_length;
};
#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb))
/* */
struct sc_capwap_fragment {
struct list_head lru_list;
uint8_t flags;
ktime_t tstamp;
uint16_t fragmentid;
struct sk_buff* fragments;
struct sk_buff* lastfragment;
int recvlength;
int totallength;
};
/* */
struct sc_capwap_fragment_queue {
spinlock_t lock;
struct list_head lru_list;
struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE];
};
/* */
struct sc_capwap_session {
struct list_head list;
struct sc_capwap_session* __rcu next;
uint16_t mtu;
union capwap_addr peeraddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t fragmentid;
spinlock_t fragmentid_lock;
struct sc_capwap_fragment_queue fragments;
};
/* */
extern union capwap_addr sc_localaddr;
/* Dipendent implementation function */
void sc_capwap_recvpacket(struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb);
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(union capwap_addr* sockaddr);
void sc_capwap_initsession(struct sc_capwap_session* session);
void sc_capwap_freesession(struct sc_capwap_session* session);
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
struct sc_capwap_packet* sc_capwap_poppacketqueue(struct sc_capwap_session* session);
void sc_capwap_pushpacketqueue(struct sc_capwap_session* session, struct sc_capwap_packet* packet);
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength);
/* Private funciotn */
#include "capwap_private.h"
#endif /* __KMOD_CAPWAP_HEADER__ */

View File

@ -0,0 +1,636 @@
#include "config.h"
#include <linux/module.h>
#include <linux/hash.h>
#include <linux/kthread.h>
#include <net/ipv6.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* Sessions */
static struct mutex sc_wtpsession_mutex;
static struct list_head sc_wtpsession_list;
static struct list_head sc_wtpsession_setup_list;
static uint32_t sc_wtpsession_size;
static uint32_t sc_wtpsession_size_shift;
static struct sc_capwap_session** __rcu sc_wtpsession_hash;
/* Threads */
static DEFINE_SPINLOCK(sc_wtpsession_threads_lock);
static uint32_t sc_wtpsession_threads_pos;
static uint32_t sc_wtpsession_threads_count;
static struct sc_capwap_workthread* sc_wtpsession_threads;
/* */
static uint32_t sc_capwap_hash(const union capwap_addr* peeraddr) {
TRACEKMOD("### sc_capwap_hash\n");
return hash_32(((peeraddr->ss.ss_family == AF_INET) ? peeraddr->sin.sin_addr.s_addr : ipv6_addr_hash(&peeraddr->sin6.sin6_addr)), sc_wtpsession_size_shift);
}
/* */
static void sc_capwap_closewtpsession(struct sc_capwap_session* wtpsession) {
TRACEKMOD("### sc_capwap_closewtpsession\n");
lockdep_assert_held(&sc_wtpsession_mutex);
/* Remove session from list reference */
if (wtpsession->peeraddr.ss.ss_family != AF_UNSPEC) {
uint32_t hash = sc_capwap_hash(&wtpsession->peeraddr);
struct sc_capwap_session* search = rcu_dereference_protected(sc_wtpsession_hash[hash], lockdep_is_held(&sc_wtpsession_mutex));
if (search) {
if (search == wtpsession) {
rcu_assign_pointer(sc_wtpsession_hash[hash], wtpsession->next);
} else {
while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != wtpsession)) {
search = rcu_dereference_protected(search->next, lockdep_is_held(&sc_wtpsession_mutex));
}
if (rcu_access_pointer(search->next)) {
rcu_assign_pointer(search->next, wtpsession->next);
}
}
}
}
/* */
list_del_rcu(&wtpsession->list);
synchronize_net();
/* Free memory */
sc_capwap_freesession(wtpsession);
kfree(wtpsession);
TRACEKMOD("*** Free session\n");
}
/* */
static void sc_capwap_closewtpsessions(void) {
struct sc_capwap_session* wtpsession;
struct sc_capwap_session* temp;
TRACEKMOD("### sc_capwap_closewtpsessions\n");
TRACEKMOD("*** Delete all sessions\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
/* */
list_for_each_entry_safe(wtpsession, temp, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete setup session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
}
/* */
list_for_each_entry_safe(wtpsession, temp, &sc_wtpsession_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete running session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
}
/* */
synchronize_net();
mutex_unlock(&sc_wtpsession_mutex);
}
/* */
static int sc_capwap_deletesetupsession(const struct sc_capwap_sessionid_element* sessionid) {
int ret = -ENOENT;
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deletesetupsession\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
list_for_each_entry(wtpsession, &sc_wtpsession_setup_list, list) {
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete setup session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
ret = 0;
break;
}
}
/* */
mutex_unlock(&sc_wtpsession_mutex);
return ret;
}
/* */
static int sc_capwap_deleterunningsession(const union capwap_addr* peeraddr) {
int ret = -ENOENT;
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deleterunningsession\n");
/* */
mutex_lock(&sc_wtpsession_mutex);
/* Search session with address hash */
wtpsession = sc_capwap_getsession(peeraddr);
if (wtpsession) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Delete running session: %s\n", sessionname);
} while(0);
#endif
sc_capwap_closewtpsession(wtpsession);
ret = 0;
}
/* */
mutex_unlock(&sc_wtpsession_mutex);
return ret;
}
/* */
static int sc_capwap_thread_recvpacket(struct sk_buff* skb) {
int ret = 1;
union capwap_addr peeraddr;
struct sc_capwap_session* session;
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_capwap_thread_recvpacket\n");
/* */
if (cb->flags & SKB_CAPWAP_FLAG_FROM_USER_SPACE) {
TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_USER_SPACE\n");
/* Get peer address */
sc_addr_fromlittle(&cb->peeraddr, &peeraddr);
TRACEKMOD("*** Address %d %x %x\n", peeraddr.ss.ss_family, (int)peeraddr.sin.sin_addr.s_addr, (int)peeraddr.sin.sin_port);
/* Send packet*/
rcu_read_lock();
session = sc_capwap_getsession(&peeraddr);
if (session) {
if (sc_capwap_forwarddata(session, cb->radioid, cb->binding, skb, 0, NULL, 0, NULL, 0)) {
TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n");
}
} else {
TRACEKMOD("*** Unable to find session\n");
}
rcu_read_unlock();
} else if (cb->flags & SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL) {
TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL\n");
/* Get peer address */
if (sc_socket_getpeeraddr(skb, &peeraddr)) {
TRACEKMOD("*** Unable get address from packet\n");
return -EINVAL;
}
/* Remove UDP header */
if (!skb_pull(skb, sizeof(struct udphdr))) {
TRACEKMOD("*** Invalid packet\n");
return -EOVERFLOW;
}
/* */
rcu_read_lock();
session = sc_capwap_getsession(&peeraddr);
ret = sc_capwap_parsingpacket(session, &peeraddr, skb);
rcu_read_unlock();
}
return ret;
}
/* */
static int sc_capwap_thread(void* data) {
struct sk_buff* skb;
struct sc_capwap_workthread* thread = (struct sc_capwap_workthread*)data;
TRACEKMOD("### sc_capwap_thread\n");
TRACEKMOD("*** Thread start\n");
for (;;) {
wait_event_interruptible(thread->waitevent, (skb_queue_len(&thread->queue) > 0) || kthread_should_stop());
if (kthread_should_stop()) {
break;
}
/* Get packet */
skb = skb_dequeue(&thread->queue);
if (!skb) {
continue;
}
/* */
TRACEKMOD("*** Thread receive packet\n");
if (sc_capwap_thread_recvpacket(skb)) {
TRACEKMOD("*** Free packet\n");
kfree_skb(skb);
}
}
TRACEKMOD("*** Thread end\n");
return 0;
}
/* */
int sc_capwap_sendkeepalive(const union capwap_addr* peeraddr) {
int ret;
int length;
struct sc_capwap_session* session;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
TRACEKMOD("### sc_capwap_sendkeepalive\n");
/* */
rcu_read_lock();
/* Get session */
session = sc_capwap_getsession(peeraddr);
if (!session) {
TRACEKMOD("*** Unknown keep-alive session\n");
ret = -ENOENT;
goto done;
}
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&session->sessionid, sessionname);
TRACEKMOD("*** Send keep-alive session: %s\n", sessionname);
} while(0);
#endif
/* Build keepalive */
length = sc_capwap_createkeepalive(&session->sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_socket_send(SOCKET_UDP, buffer, length, &session->peeraddr);
if (ret > 0) {
ret = 0;
}
done:
rcu_read_unlock();
return ret;
}
/* */
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) {
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_newsession\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Create session: %s\n", sessionname);
} while(0);
#endif
/* */
session = kzalloc(sizeof(struct sc_capwap_session), GFP_KERNEL);
if (!session) {
TRACEKMOD("*** Unable to create session\n");
return -ENOMEM;
}
/* Initialize session */
sc_capwap_initsession(session);
memcpy(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
session->mtu = mtu;
/* Add to setup session list */
mutex_lock(&sc_wtpsession_mutex);
list_add_rcu(&session->list, &sc_wtpsession_setup_list);
mutex_unlock(&sc_wtpsession_mutex);
TRACEKMOD("*** Create session\n");
return 0;
}
/* */
int sc_capwap_init(uint32_t hash, uint32_t threads) {
uint32_t i;
int err = -ENOMEM;
TRACEKMOD("### sc_capwap_init\n");
TRACEKMOD("*** Init capwap module - hash bitfield: %u - threads: %u\n", hash, threads);
/* Init session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
mutex_init(&sc_wtpsession_mutex);
INIT_LIST_HEAD(&sc_wtpsession_list);
INIT_LIST_HEAD(&sc_wtpsession_setup_list);
sc_wtpsession_size_shift = hash;
sc_wtpsession_size = 1 << hash;
sc_wtpsession_hash = (struct sc_capwap_session**)kzalloc(sizeof(struct sc_capwap_session*) * sc_wtpsession_size, GFP_KERNEL);
if (!sc_wtpsession_hash) {
goto error;
}
/* Create threads */
sc_wtpsession_threads_pos = 0;
sc_wtpsession_threads_count = threads;
sc_wtpsession_threads = (struct sc_capwap_workthread*)kzalloc(sizeof(struct sc_capwap_workthread) * threads, GFP_KERNEL);
if (!sc_wtpsession_threads) {
goto error2;
}
for (i = 0; i < threads; i++) {
sc_wtpsession_threads[i].thread = kthread_create(sc_capwap_thread, &sc_wtpsession_threads[i], "smartcapwap/%u", i);
if (IS_ERR(sc_wtpsession_threads[i].thread)) {
err = PTR_ERR(sc_wtpsession_threads[i].thread);
sc_wtpsession_threads[i].thread = NULL;
goto error3;
}
}
/* Init sockect */
err = sc_socket_init();
if (err) {
goto error3;
}
/* Start threads */
for (i = 0; i < threads; i++) {
skb_queue_head_init(&sc_wtpsession_threads[i].queue);
init_waitqueue_head(&sc_wtpsession_threads[i].waitevent);
wake_up_process(sc_wtpsession_threads[i].thread);
}
return 0;
error3:
for (i = 0; i < threads; i++) {
if (sc_wtpsession_threads[i].thread) {
kthread_stop(sc_wtpsession_threads[i].thread);
}
}
kfree(sc_wtpsession_threads);
error2:
kfree(sc_wtpsession_hash);
error:
return err;
}
/* */
void sc_capwap_close(void) {
uint32_t i;
TRACEKMOD("### sc_capwap_close\n");
TRACEKMOD("*** Closing capwap module\n");
sc_socket_close();
/* */
for (i = 0; i < sc_wtpsession_threads_count; i++) {
kthread_stop(sc_wtpsession_threads[i].thread);
}
kfree(sc_wtpsession_threads);
/* */
sc_capwap_closewtpsessions();
mutex_destroy(&sc_wtpsession_mutex);
kfree(sc_wtpsession_hash);
TRACEKMOD("*** Close capwap module\n");
}
/* */
int sc_capwap_deletesession(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) {
struct sc_capwap_session* wtpsession;
TRACEKMOD("### sc_capwap_deletesession\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Delete session: %s\n", sessionname);
} while(0);
#endif
/* Searching item with read lock */
rcu_read_lock();
/* Search into running session list */
if (sockaddr && sc_capwap_getsession(sockaddr)) {
rcu_read_unlock();
/* Remove session with address */
return sc_capwap_deleterunningsession(sockaddr);
} else {
list_for_each_entry_rcu(wtpsession, &sc_wtpsession_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Check running session for delete: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
union capwap_addr peeraddr;
/* Get peer address */
memcpy(&peeraddr, &wtpsession->peeraddr, sizeof(union capwap_addr));
rcu_read_unlock();
/* Remove session with address */
return sc_capwap_deleterunningsession(&peeraddr);
}
}
}
/* Search into setup session list */
list_for_each_entry_rcu(wtpsession, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&wtpsession->sessionid, sessionname);
TRACEKMOD("*** Check setup session for delete: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&wtpsession->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
rcu_read_unlock();
/* Remove session with sessionid */
return sc_capwap_deletesetupsession(sessionid);
}
}
rcu_read_unlock();
TRACEKMOD("*** Session not found\n");
return -ENOENT;
}
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) {
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_getsession\n");
/* */
session = rcu_dereference_check(sc_wtpsession_hash[sc_capwap_hash(sockaddr)], lockdep_is_held(&sc_wtpsession_mutex));
while (session) {
if (!sc_addr_compare(sockaddr, &session->peeraddr)) {
break;
}
/* */
session = rcu_dereference_check(session->next, lockdep_is_held(&sc_wtpsession_mutex));
}
return session;
}
/* */
void sc_capwap_recvpacket(struct sk_buff* skb) {
uint32_t pos;
unsigned long flags;
TRACEKMOD("### sc_capwap_recvpacket\n");
spin_lock_irqsave(&sc_wtpsession_threads_lock, flags);
sc_wtpsession_threads_pos = ((sc_wtpsession_threads_pos + 1) % sc_wtpsession_threads_count);
pos = sc_wtpsession_threads_pos;
spin_unlock_irqrestore(&sc_wtpsession_threads_lock, flags);
TRACEKMOD("*** Add packet to thread: %u\n", pos);
/* Queue packet */
skb_queue_tail(&sc_wtpsession_threads[pos].queue, skb);
wake_up_interruptible(&sc_wtpsession_threads[pos].waitevent);
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
uint32_t hash;
struct sc_capwap_session* search;
struct sc_capwap_session* wtpsession = NULL;
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(sessionid, sessionname);
TRACEKMOD("*** Receive unknown keep-alive: %s\n", sessionname);
} while(0);
#endif
/* Change read lock to update lock */
rcu_read_unlock();
mutex_lock(&sc_wtpsession_mutex);
/* Search and remove from setup session */
list_for_each_entry(search, &sc_wtpsession_setup_list, list) {
#ifdef DEBUGKMOD
do {
char sessionname[33];
sc_capwap_sessionid_printf(&search->sessionid, sessionname);
TRACEKMOD("*** Check setup session: %s\n", sessionname);
} while(0);
#endif
if (!memcmp(&search->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
wtpsession = search;
break;
}
}
/* */
if (wtpsession) {
TRACEKMOD("*** Setup session found\n");
list_del_rcu(&wtpsession->list);
synchronize_net();
} else {
TRACEKMOD("*** Setup session not found\n");
goto done;
}
/* */
hash = sc_capwap_hash(sockaddr);
memcpy(&wtpsession->peeraddr, sockaddr, sizeof(union capwap_addr));
/* Add to list */
list_add_rcu(&wtpsession->list, &sc_wtpsession_list);
wtpsession->next = sc_wtpsession_hash[hash];
rcu_assign_pointer(sc_wtpsession_hash[hash], wtpsession);
done:
rcu_read_lock();
mutex_unlock(&sc_wtpsession_mutex);
/* */
return wtpsession;
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) {
uint8_t* pos;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
struct sc_capwap_radio_addr* radioaddr = NULL;
int radioaddrsize = 0;
struct sc_capwap_wireless_information* winfo = NULL;
int winfosize = 0;
TRACEKMOD("### sc_capwap_parsingdatapacket\n");
/* Retrieve optional attribute */
pos = skb->data + sizeof(struct sc_capwap_header);
if (IS_FLAG_M_HEADER(header)) {
radioaddr = (struct sc_capwap_radio_addr*)pos;
radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3;
pos += radioaddrsize;
}
if (IS_FLAG_W_HEADER(header)) {
winfo = (struct sc_capwap_wireless_information*)pos;
radioaddrsize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3;
pos += winfosize;
}
/* TODO */
}
/* */
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingmgmtpacket\n");
/* Send packet with capwap header into userspace */
sc_netlink_notify_recv_data(&session->sessionid, skb->data, skb->len);
}

View File

@ -0,0 +1,26 @@
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
#define __KMOD_CAPWAP_PRIVATE_HEADER__
/* */
struct sc_capwap_workthread {
struct task_struct* thread;
struct sk_buff_head queue;
wait_queue_head_t waitevent;
};
/* */
int sc_capwap_init(uint32_t hash, uint32_t threads);
void sc_capwap_close(void);
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr);
/* */
int sc_capwap_sendkeepalive(const union capwap_addr* peeraddr);
/* */
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint16_t mtu);
int sc_capwap_deletesession(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

172
src/ac/kmod/capwap_rfc.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef __KMOD_CAPWAP_RFC_HEADER__
#define __KMOD_CAPWAP_RFC_HEADER__
#include <linux/types.h>
#include <asm/byteorder.h>
/* */
#define CAPWAP_RADIOID_MAX_COUNT 31
#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT))
#define CAPWAP_WLANID_MAX_COUNT 16
#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT))
/* */
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_ELEMENT_SESSIONID 35
/* */
#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \
sizeof(struct sc_capwap_header) + \
sizeof(struct sc_capwap_data_message) + \
sizeof(struct sc_capwap_message_element) + \
sizeof(struct sc_capwap_sessionid_element))
/* Preamble */
struct sc_capwap_preamble {
#if defined(__BIG_ENDIAN_BITFIELD)
uint8_t version: 4,
type: 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t type: 4,
version: 4;
#endif
} __packed;
/* DTLS header */
struct sc_capwap_dtls_header {
struct sc_capwap_preamble preamble;
uint8_t reserved[3];
} __packed;
/* Plain header */
struct sc_capwap_header {
struct sc_capwap_preamble preamble;
#if defined(__BIG_ENDIAN_BITFIELD)
uint16_t hlen: 5,
rid: 5,
wbid: 5,
flag_t: 1;
uint8_t flag_f: 1,
flag_l: 1,
flag_w: 1,
flag_m: 1,
flag_k: 1,
flag_res: 3;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint16_t _rid_hi: 3,
hlen: 5,
flag_t: 1,
wbid: 5,
_rid_lo: 2;
uint8_t flag_res: 3,
flag_k: 1,
flag_m: 1,
flag_w: 1,
flag_l: 1,
flag_f: 1;
#endif
__be16 frag_id;
__be16 frag_off;
} __packed;
/* Mac Address */
#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8
#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12
#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12
struct sc_capwap_radio_addr {
uint8_t length;
} __packed;
/* Wireless Information */
#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8
#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8
#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8
struct sc_capwap_wireless_information {
uint8_t length;
} __packed;
/* IEEE802.11 Wireless Information */
struct sc_capwap_ieee80211_frame_info {
uint8_t rssi;
uint8_t snr;
__be16 rate;
} __packed;
/* */
#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED)
/* Data channel message */
struct sc_capwap_data_message {
__be16 length;
} __packed;
/* Message element */
struct sc_capwap_message_element {
__be16 type;
__be16 length;
} __packed;
/* Session id message element */
struct sc_capwap_sessionid_element {
uint8_t id[16];
} __packed;
/* */
#define MACADDRESS_EUI48_LENGTH 6
struct sc_capwap_macaddress_eui48 {
uint8_t addr[MACADDRESS_EUI48_LENGTH];
} __packed;
/* */
#define MACADDRESS_EUI64_LENGTH 8
struct sc_capwap_macaddress_eui64 {
uint8_t addr[MACADDRESS_EUI64_LENGTH];
} __packed;
/* Capwap preamble */
#define CAPWAP_PROTOCOL_VERSION 0
#define CAPWAP_PREAMBLE_HEADER 0
#define CAPWAP_PREAMBLE_DTLS_HEADER 1
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element))
/* */
#define GET_VERSION_HEADER(x) ((x)->preamble.version)
#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y))
#define GET_TYPE_HEADER(x) ((x)->preamble.type)
#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y))
#define GET_HLEN_HEADER(x) ((x)->hlen)
#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y))
#if defined(__BIG_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((x)->rid))
#define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y))
#elif defined(__LITTLE_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo)))
#define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); })
#endif
#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid))
#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y))
#define IS_FLAG_T_HEADER(x) ((x)->flag_t)
#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0))
#define IS_FLAG_F_HEADER(x) ((x)->flag_f)
#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0))
#define IS_FLAG_L_HEADER(x) ((x)->flag_l)
#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0))
#define IS_FLAG_W_HEADER(x) ((x)->flag_w)
#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0))
#define IS_FLAG_M_HEADER(x) ((x)->flag_m)
#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0))
#define IS_FLAG_K_HEADER(x) ((x)->flag_k)
#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0))
#endif /* __KMOD_CAPWAP_RFC_HEADER__ */

13
src/ac/kmod/config.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __KMOD_CONFIG_HEADER__
#define __KMOD_CONFIG_HEADER__
#define DEBUGKMOD 1
#ifdef DEBUGKMOD
#define TRACEKMOD(s, args...) printk(s, ##args)
#else
#define TRACEKMOD(s, args...)
#endif
#endif /* __KMOD_CONFIG_HEADER__ */

View File

@ -1,21 +1,29 @@
#include "config.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include "netlinkapp.h" #include "netlinkapp.h"
/* */ /* */
static int __init smartcapwap_ac_init(void) { static int __init smartcapwap_ac_init(void) {
int result = 0; int ret;
/* */ TRACEKMOD("### smartcapwap_ac_init\n");
result = nlsmartcapwap_ac_init();
return result; /* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
} }
module_init(smartcapwap_ac_init); module_init(smartcapwap_ac_init);
/* */ /* */
static void __exit smartcapwap_ac_exit(void) { static void __exit smartcapwap_ac_exit(void) {
nlsmartcapwap_ac_exit(); TRACEKMOD("### smartcapwap_ac_exit\n");
sc_netlink_exit();
} }
module_exit(smartcapwap_ac_exit); module_exit(smartcapwap_ac_exit);

View File

@ -1,5 +1,8 @@
#include "config.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <net/genetlink.h> #include <net/genetlink.h>
@ -9,90 +12,251 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include "nlsmartcapwap.h" #include "nlsmartcapwap.h"
#include "netlinkapp.h" #include "netlinkapp.h"
#include "capwap.h"
/* */ /* */
struct nlsmartcapwap_ac_device { static u32 sc_netlink_usermodeid;
struct list_head list;
u32 usermodeid;
};
/* */ /* */
static u32 nlsmartcapwap_ac_usermodeid = 0; static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
static LIST_HEAD(nlsmartcapwap_ac_dev_list); TRACEKMOD("### sc_netlink_pre_doit\n");
/* Netlink Family */
static struct genl_family nlsmartcapwap_ac_family = {
.id = GENL_ID_GENERATE,
.name = SMARTCAPWAP_AC_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_AC_ATTR_MAX,
.netnsok = true,
};
/* */
static void nlsmartcapwap_ac_free_device(struct nlsmartcapwap_ac_device* nldev) {
/* Free memory */
kfree(nldev);
}
/* */
static void nlsmartcapwap_ac_close(void) {
struct nlsmartcapwap_ac_device* nldev;
struct nlsmartcapwap_ac_device* tmp;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_ac_dev_list, list) {
list_del(&nldev->list);
/* Free device */
nlsmartcapwap_ac_free_device(nldev);
}
}
/* */
static int nlsmartcapwap_ac_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
u32 portid = info->snd_pid;
#else
u32 portid = info->snd_portid;
#endif
rtnl_lock(); rtnl_lock();
return 0;
}
if (!nlsmartcapwap_ac_usermodeid) { /* */
nlsmartcapwap_ac_usermodeid = portid; static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
} else if (nlsmartcapwap_ac_usermodeid == portid) { TRACEKMOD("### sc_netlink_post_doit\n");
ret = -EALREADY;
} else {
ret = -EBUSY;
}
rtnl_unlock(); rtnl_unlock();
}
/* Netlink Family */
static struct genl_family sc_netlink_family = {
.id = GENL_ID_GENERATE,
.name = NLSMARTCAPWAP_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_ATTR_MAX,
.netnsok = true,
.pre_doit = sc_netlink_pre_doit,
.post_doit = sc_netlink_post_doit,
};
/* */
static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) {
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_bind\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(&sockaddr);
}
/* */
static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) {
int ret;
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_send_keepalive\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) {
return -EINVAL;
}
/* */
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Send keep-alive packet */
ret = sc_capwap_sendkeepalive(&sockaddr);
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) {
int length;
struct sk_buff* skbdata;
union capwap_addr sockaddr;
struct sc_skb_capwap_cb* cb;
TRACEKMOD("### sc_netlink_send_data\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
} else if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
return -EINVAL;
}
/* */
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Create socket buffer */
length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]);
skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL);
if (!skbdata) {
return -ENOMEM;
}
/* Reserve space for Capwap Header */
skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH);
/* Copy data into socket buffer */
memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length);
/* */
cb = CAPWAP_SKB_CB(skbdata);
cb->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE | SKB_CAPWAP_FLAG_PEERADDRESS | SKB_CAPWAP_FLAG_RADIOID | SKB_CAPWAP_FLAG_BINDING;
sc_addr_tolittle(&sockaddr, &cb->peeraddr);
cb->radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
cb->binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]);
/* */
sc_capwap_recvpacket(skbdata);
return 0;
}
/* */
static int sc_netlink_new_session(struct sk_buff* skb, struct genl_info* info) {
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_new_session\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session ID */
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element))) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) {
return -EINVAL;
}
}
/* New session */
return sc_capwap_newsession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), mtu);
}
/* */
static int sc_netlink_delete_session(struct sk_buff* skb, struct genl_info* info) {
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_delete_session\n");
/* Check Link */
if (sc_netlink_usermodeid != info->snd_portid) {
return -ENOLINK;
}
/* Check Session ID */
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element))) {
return -EINVAL;
}
/* Check Address */
if (info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) == sizeof(struct sockaddr_storage))) {
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
} else {
sockaddr.ss.ss_family = AF_UNSPEC;
}
/* Delete session */
return sc_capwap_deletesession(((sockaddr.ss.ss_family == AF_UNSPEC) ? NULL : &sockaddr), (struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]));
}
/* */
static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
TRACEKMOD("### sc_netlink_link\n");
if (!info->attrs[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD] || !info->attrs[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT]) {
TRACEKMOD("*** Invalid link argument\n");
return -EINVAL;
}
if (!sc_netlink_usermodeid) {
uint32_t hash = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD]);
uint32_t threads = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT]);
if (!hash || !threads) {
TRACEKMOD("*** Invalid link argument: %u %u\n", hash, threads);
return -EINVAL;
}
/* Initialize library */
ret = sc_capwap_init(hash, threads);
if (!ret) {
sc_netlink_usermodeid = info->snd_portid;
/* Deny unload module */
try_module_get(THIS_MODULE);
}
} else if (sc_netlink_usermodeid == info->snd_portid) {
TRACEKMOD("*** Already link\n");
ret = -EALREADY;
} else {
TRACEKMOD("*** Busy kernel link\n");
ret = -EBUSY;
}
return ret; return ret;
} }
/* */ /* */
static int nlsmartcapwap_ac_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
struct netlink_notify* notify = (struct netlink_notify*)_notify; struct netlink_notify* notify = (struct netlink_notify*)_notify;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
u32 portid = notify->pid;
#else
u32 portid = notify->portid;
#endif
/* */ /* */
if (state == NETLINK_URELEASE) { if (state == NETLINK_URELEASE) {
rtnl_lock(); rtnl_lock();
if (nlsmartcapwap_ac_usermodeid == portid) { if (sc_netlink_usermodeid == notify->portid) {
nlsmartcapwap_ac_usermodeid = 0; /* Close capwap engine */
sc_capwap_close();
/* Close all devices */ /* Allow unload module */
nlsmartcapwap_ac_close(); module_put(THIS_MODULE);
sc_netlink_usermodeid = 0;
} }
rtnl_unlock(); rtnl_unlock();
@ -102,57 +266,172 @@ static int nlsmartcapwap_ac_netlink_notify(struct notifier_block* nb, unsigned l
} }
/* */ /* */
static const struct nla_policy nlsmartcapwap_ac_policy[NLSMARTCAPWAP_AC_ATTR_MAX + 1] = { static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_AC_ATTR_FLAGS] = { .type = NLA_U32 }, [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN + CAPWAP_HEADER_MAX_LENGTH },
[NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT] = { .type = NLA_U32 },
}; };
/* Netlink Ops */ /* Netlink Ops */
static struct genl_ops nlsmartcapwap_ac_ops[] = { static struct genl_ops sc_netlink_ops[] = {
{ {
.cmd = NLSMARTCAPWAP_AC_CMD_LINK, .cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = nlsmartcapwap_ac_link, .doit = sc_netlink_link,
.policy = nlsmartcapwap_ac_policy, .policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_BIND,
.doit = sc_netlink_bind,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
.doit = sc_netlink_send_keepalive,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_DATA,
.doit = sc_netlink_send_data,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_NEW_SESSION,
.doit = sc_netlink_new_session,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_DELETE_SESSION,
.doit = sc_netlink_delete_session,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
}; };
/* Netlink notify */ /* Netlink notify */
static struct notifier_block nlsmartcapwap_ac_netlink_notifier = { static struct notifier_block sc_netlink_notifier = {
.notifier_call = nlsmartcapwap_ac_netlink_notify, .notifier_call = sc_netlink_notify,
}; };
/* */ /* */
int nlsmartcapwap_ac_init(void) { int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_keepalive\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr->ss) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_data\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_init(void) {
int ret; int ret;
TRACEKMOD("### sc_netlink_init\n");
/* */
sc_netlink_usermodeid = 0;
/* Register netlink family */ /* Register netlink family */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops, sizeof(nlsmartcapwap_ac_ops) / sizeof(nlsmartcapwap_ac_ops[0])); ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops, sizeof(sc_netlink_ops) / sizeof(sc_netlink_ops[0]));
#else #else
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops); ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops);
#endif #endif
if (ret) { if (ret) {
return ret; goto error;
} }
/* Register netlink notifier */ /* Register netlink notifier */
ret = netlink_register_notifier(&nlsmartcapwap_ac_netlink_notifier); ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) { if (ret) {
genl_unregister_family(&nlsmartcapwap_ac_family); goto error2;
return ret;
} }
return 0;
error2:
genl_unregister_family(&sc_netlink_family);
error:
return ret; return ret;
} }
/* */ /* */
void nlsmartcapwap_ac_exit(void) { void sc_netlink_exit(void) {
/* */ TRACEKMOD("### sc_netlink_exit\n");
rtnl_lock();
nlsmartcapwap_ac_close();
rtnl_unlock();
/* */ netlink_unregister_notifier(&sc_netlink_notifier);
netlink_unregister_notifier(&nlsmartcapwap_ac_netlink_notifier); genl_unregister_family(&sc_netlink_family);
genl_unregister_family(&nlsmartcapwap_ac_family);
} }

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_AC_NETLINKAPP_HEADER__ #ifndef __KMOD_AC_NETLINKAPP_HEADER__
#define __KMOD_AC_NETLINKAPP_HEADER__ #define __KMOD_AC_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */ /* */
int nlsmartcapwap_ac_init(void); int sc_netlink_init(void);
void nlsmartcapwap_ac_exit(void); void sc_netlink_exit(void);
/* */
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length);
#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */ #endif /* __KMOD_AC_NETLINKAPP_HEADER__ */

View File

@ -2,28 +2,55 @@
#define __AC_NLSMARTCAPWAP_HEADER__ #define __AC_NLSMARTCAPWAP_HEADER__
/* */ /* */
#define SMARTCAPWAP_AC_GENL_NAME "smartcapwap_ac" #define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac"
/* */ /* */
enum nlsmartcapwap_ac_attrs { #define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
NLSMARTCAPWAP_AC_ATTR_UNSPEC,
NLSMARTCAPWAP_AC_ATTR_FLAGS, /* */
enum sc_netlink_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_FLAGS,
NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_RADIOID,
NLSMARTCAPWAP_ATTR_BINDING,
NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_HASH_SESSION_BITFIELD,
NLSMARTCAPWAP_ATTR_SESSION_THREADS_COUNT,
/* Last attribute */ /* Last attribute */
__NLSMARTCAPWAP_AC_ATTR_AFTER_LAST, __NLSMARTCAPWAP_ATTR_AFTER_LAST,
NLSMARTCAPWAP_AC_ATTR_MAX = __NLSMARTCAPWAP_AC_ATTR_AFTER_LAST - 1 NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
}; };
/* */ /* */
enum nlsmartcapwap_ac_commands { enum sc_netlink_commands {
NLSMARTCAPWAP_AC_CMD_UNSPEC, NLSMARTCAPWAP_CMD_UNSPEC,
NLSMARTCAPWAP_AC_CMD_LINK, NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_NEW_SESSION,
NLSMARTCAPWAP_CMD_DELETE_SESSION,
NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
/* Last command */ /* Last command */
__NLSMARTCAPWAP_AC_CMD_AFTER_LAST, __NLSMARTCAPWAP_CMD_AFTER_LAST,
NLSMARTCAPWAP_AC_CMD_MAX = __NLSMARTCAPWAP_AC_CMD_AFTER_LAST - 1 NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
}; };
#endif /* __AC_NLSMARTCAPWAP_HEADER__ */ #endif /* __AC_NLSMARTCAPWAP_HEADER__ */

257
src/ac/kmod/socket.c Normal file
View File

@ -0,0 +1,257 @@
#include "config.h"
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/kthread.h>
#include <linux/net.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <net/ipv6.h>
#include <net/sock.h>
#include <net/udp.h>
#include "socket.h"
#include "capwap.h"
/* Socket */
#define SOCKET_COUNT 2
static struct socket* sc_sockets[SOCKET_COUNT];
/* */
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_socket_recvpacket\n");
/* */
cb->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
/* */
sc_capwap_recvpacket(skb);
return 0;
}
/* */
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
int ret;
TRACEKMOD("### sc_socket_create\n");
/* Create socket */
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
if (ret) {
goto failure;
}
/* Bind to interface */
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
if (ret) {
goto failure2;
}
/* Set callback */
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
/* */
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
union capwap_addr localaddr;
int localaddrsize = sizeof(union capwap_addr);
/* Retrieve port */
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
if (ret) {
goto failure2;
}
/* */
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
sockaddr->sin.sin_port = localaddr.sin.sin_port;
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
} else {
ret = -EFAULT;
goto failure2;
}
}
return ret;
failure2:
sock_release(sc_sockets[type]);
sc_sockets[type] = 0;
failure:
return ret;
}
/* */
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
unsigned char* nethdr;
TRACEKMOD("### sc_socket_getpeeraddr\n");
/* */
nethdr = skb_network_header(skb);
if (!nethdr) {
return -EINVAL;
}
/* */
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {
/* Validate IPv4 header */
if ((nethdr[0] & 0xf0) != 0x40) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin.sin_family = AF_INET;
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
peeraddr->sin.sin_port = udp_hdr(skb)->source;
break;
}
case ETH_P_IPV6: {
/* Validate IPv6 header */
if ((nethdr[0] & 0xf0) != 0x60) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin6.sin6_family = AF_INET6;
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
break;
}
default: {
return -EINVAL;
}
}
return 0;
}
/* */
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
struct kvec vec;
struct msghdr msg;
TRACEKMOD("### sc_socket_send\n");
/* */
vec.iov_base = buffer;
vec.iov_len = length;
/* */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = sockaddr;
msg.msg_namelen = sizeof(union capwap_addr);
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
/* */
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
}
/* */
int sc_socket_init(void) {
TRACEKMOD("### sc_socket_init\n");
memset(sc_sockets, 0, sizeof(sc_sockets));
return 0;
}
/* */
int sc_socket_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_socket_bind\n");
/* */
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
return -EBUSY;
}
/* UDP socket */
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
if (ret) {
goto failure;
}
/* UDPLite socket */
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
if (ret) {
goto failure;
}
/* */
udp_encap_enable();
if (sockaddr->ss.ss_family == AF_INET6) {
udpv6_encap_enable();
}
return 0;
failure:
sc_socket_close();
return ret;
}
/* */
void sc_socket_close(void) {
TRACEKMOD("### sc_socket_close\n");
/* Close sockets */
if (sc_sockets[SOCKET_UDP]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDP]);
}
if (sc_sockets[SOCKET_UDPLITE]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDPLITE]);
}
memset(sc_sockets, 0, sizeof(sc_sockets));
}
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
TRACEKMOD("### sc_addr_compare\n");
if (addr1->ss.ss_family == addr2->ss.ss_family) {
if (addr1->ss.ss_family == AF_INET) {
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
} else if (addr1->ss.ss_family == AF_INET6) {
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
}
}
return -1;
}
/* */
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little) {
little->family = (uint8_t)addr->ss.ss_family;
if (addr->ss.ss_family == AF_INET) {
memcpy(&little->addr4, &addr->sin.sin_addr, sizeof(struct in_addr));
little->port = addr->sin.sin_port;
} else if (addr->ss.ss_family == AF_INET6) {
memcpy(&little->addr6, &addr->sin6.sin6_addr, sizeof(struct in6_addr));
little->port = addr->sin6.sin6_port;
}
}
/* */
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr) {
memset(addr, 0, sizeof(union capwap_addr));
addr->ss.ss_family = little->family;
if (little->family == AF_INET) {
memcpy(&addr->sin.sin_addr, &little->addr4, sizeof(struct in_addr));
addr->sin.sin_port = little->port;
} else if (little->family == AF_INET6) {
memcpy(&addr->sin6.sin6_addr, &little->addr6, sizeof(struct in6_addr));
addr->sin6.sin6_port = little->port;
}
}

45
src/ac/kmod/socket.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __KMOD_SOCKET_HEADER__
#define __KMOD_SOCKET_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
/* */
#define SOCKET_UDP 0
#define SOCKET_UDPLITE 1
/* Little socket address */
struct capwap_addr_little {
uint8_t family;
union {
struct in_addr addr4;
struct in6_addr addr6;
};
uint16_t port;
};
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
/* */
int sc_socket_init(void);
void sc_socket_close(void);
/* */
int sc_socket_bind(union capwap_addr* sockaddr);
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little);
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr);
#endif /* __KMOD_SOCKET_HEADER__ */

View File

@ -13,7 +13,6 @@
#include "capwap_logging.h" #include "capwap_logging.h"
#include "capwap_error.h" #include "capwap_error.h"
#define CANARY 0xaaaaaaaa
#define BACKTRACE_BUFFER 256 #define BACKTRACE_BUFFER 256
#ifndef DEBUG_BREAKPOINT #ifndef DEBUG_BREAKPOINT
@ -46,8 +45,8 @@ void* capwap_alloc_debug(size_t size, const char* file, const int line) {
exit(CAPWAP_ASSERT_CONDITION); exit(CAPWAP_ASSERT_CONDITION);
} }
/* Alloc block with memory block and canary */ /* Alloc block with memory block */
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size + 4); block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size);
if (!block) { if (!block) {
capwap_logging_debug("Out of memory %s(%d)", file, line); capwap_logging_debug("Out of memory %s(%d)", file, line);
DEBUG_BREAKPOINT(); DEBUG_BREAKPOINT();
@ -64,9 +63,6 @@ void* capwap_alloc_debug(size_t size, const char* file, const int line) {
#endif #endif
block->next = g_memoryblocks; block->next = g_memoryblocks;
/* Canary */
*((unsigned long*)(((char*)block->item) + block->size)) = CANARY;
g_memoryblocks = block; g_memoryblocks = block;
return block->item; return block->item;
@ -98,13 +94,6 @@ void capwap_free_debug(void* p, const char* file, const int line) {
return; 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 */ /* Find memory block */
prevblock = NULL; prevblock = NULL;
findblock = g_memoryblocks; findblock = g_memoryblocks;

View File

@ -22,7 +22,7 @@ void capwap_dump_memory(void);
#ifdef USE_DEBUG_BACKTRACE #ifdef USE_DEBUG_BACKTRACE
void capwap_backtrace_callstack(void); void capwap_backtrace_callstack(void);
#else #else
#define capwap_backtrace_callstack() (0) #define capwap_backtrace_callstack()
#endif #endif
#else #else
@ -34,9 +34,9 @@ void capwap_backtrace_callstack(void);
/* Standard memory management */ /* Standard memory management */
#define capwap_alloc(l) ({ void* __x = malloc(l); if (!__x) capwap_outofmemory(); __x; }) #define capwap_alloc(l) ({ void* __x = malloc(l); if (!__x) capwap_outofmemory(); __x; })
#define capwap_free(x) free(x) #define capwap_free(x) free(x)
#define capwap_check_memory_leak(x) (0) #define capwap_check_memory_leak(x)
#define capwap_dump_memory() (0) #define capwap_dump_memory()
#define capwap_backtrace_callstack() (0) #define capwap_backtrace_callstack()
#endif #endif

View File

@ -72,7 +72,7 @@ static int capwap_bio_method_send(CYASSL* ssl, char* buffer, int length, void* c
memcpy(&data[0] + sizeof(struct capwap_dtls_header), buffer, length); memcpy(&data[0] + sizeof(struct capwap_dtls_header), buffer, length);
/* Send packet */ /* Send packet */
if (!dtls->send(dtls, data, length + sizeof(struct capwap_dtls_header), dtls->sendparam)) { if (capwap_sendto(dtls->sock, data, length + sizeof(struct capwap_dtls_header), &dtls->peeraddr) <= 0) {
return CYASSL_CBIO_ERR_GENERAL; return CYASSL_CBIO_ERR_GENERAL;
} }
@ -196,18 +196,14 @@ static int capwap_crypt_createcookie(CYASSL* ssl, unsigned char* buffer, int siz
} }
/* Create buffer with peer's address and port */ /* Create buffer with peer's address and port */
if (dtls->peeraddr.ss_family == AF_INET) { if (dtls->peeraddr.ss.ss_family == AF_INET) {
struct sockaddr_in* peeripv4 = (struct sockaddr_in*)&dtls->peeraddr;
length = sizeof(struct in_addr) + sizeof(in_port_t); length = sizeof(struct in_addr) + sizeof(in_port_t);
memcpy(temp, &peeripv4->sin_port, sizeof(in_port_t)); memcpy(temp, &dtls->peeraddr.sin.sin_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &peeripv4->sin_addr, sizeof(struct in_addr)); memcpy(temp + sizeof(in_port_t), &dtls->peeraddr.sin.sin_addr, sizeof(struct in_addr));
} else if (dtls->peeraddr.ss_family == AF_INET6) { } else if (dtls->peeraddr.ss.ss_family == AF_INET6) {
struct sockaddr_in6* peeripv6 = (struct sockaddr_in6*)&dtls->peeraddr;
length = sizeof(struct in6_addr) + sizeof(in_port_t); length = sizeof(struct in6_addr) + sizeof(in_port_t);
memcpy(temp, &peeripv6->sin6_port, sizeof(in_port_t)); memcpy(temp, &dtls->peeraddr.sin6.sin6_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &peeripv6->sin6_addr, sizeof(struct in6_addr)); memcpy(temp + sizeof(in_port_t), &dtls->peeraddr.sin6.sin6_addr, sizeof(struct in6_addr));
} else { } else {
return -1; return -1;
} }
@ -376,14 +372,11 @@ 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) { int capwap_crypt_createsession(struct capwap_dtls* dtls, struct capwap_dtls_context* dtlscontext) {
ASSERT(dtls != NULL); ASSERT(dtls != NULL);
ASSERT(dtlscontext != NULL); ASSERT(dtlscontext != NULL);
ASSERT(dtlscontext->sslcontext != NULL); ASSERT(dtlscontext->sslcontext != NULL);
ASSERT(biosend != NULL);
memset(dtls, 0, sizeof(struct capwap_dtls));
/* Create ssl session */ /* Create ssl session */
dtls->sslsession = (void*)CyaSSL_new((CYASSL_CTX*)dtlscontext->sslcontext); dtls->sslsession = (void*)CyaSSL_new((CYASSL_CTX*)dtlscontext->sslcontext);
if (!dtls->sslsession) { if (!dtls->sslsession) {
@ -391,10 +384,6 @@ int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct
return 0; return 0;
} }
/* Send callback */
dtls->send = biosend;
dtls->sendparam = param;
/* */ /* */
CyaSSL_set_using_nonblock((CYASSL*)dtls->sslsession, 1); CyaSSL_set_using_nonblock((CYASSL*)dtls->sslsession, 1);
CyaSSL_SetIOReadCtx((CYASSL*)dtls->sslsession, (void*)dtls); CyaSSL_SetIOReadCtx((CYASSL*)dtls->sslsession, (void*)dtls);
@ -403,10 +392,11 @@ int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct
/* */ /* */
dtls->action = CAPWAP_DTLS_ACTION_NONE; dtls->action = CAPWAP_DTLS_ACTION_NONE;
dtls->session = sessiontype;
dtls->dtlscontext = dtlscontext; dtls->dtlscontext = dtlscontext;
dtls->enable = 1; dtls->enable = 1;
dtls->buffer = NULL;
dtls->length = 0;
return 1; return 1;
} }
@ -445,8 +435,28 @@ static int capwap_crypt_handshake(struct capwap_dtls* dtls) {
} }
/* */ /* */
int capwap_crypt_open(struct capwap_dtls* dtls, struct sockaddr_storage* peeraddr) { void capwap_crypt_setconnection(struct capwap_dtls* dtls, int sock, union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr) {
memcpy(&dtls->peeraddr, peeraddr, sizeof(struct sockaddr_storage)); ASSERT(sock >= 0);
ASSERT(localaddr != NULL);
ASSERT(peeraddr != NULL);
dtls->sock = sock;
/* */
memcpy(&dtls->localaddr, localaddr, sizeof(union sockaddr_capwap));
if (dtls->localaddr.ss.ss_family == AF_INET6) {
capwap_ipv4_mapped_ipv6(&dtls->localaddr);
}
/* */
memcpy(&dtls->peeraddr, peeraddr, sizeof(union sockaddr_capwap));
if (dtls->peeraddr.ss.ss_family == AF_INET6) {
capwap_ipv4_mapped_ipv6(&dtls->peeraddr);
}
}
/* */
int capwap_crypt_open(struct capwap_dtls* dtls) {
return capwap_crypt_handshake(dtls); return capwap_crypt_handshake(dtls);
} }
@ -473,15 +483,15 @@ void capwap_crypt_freesession(struct capwap_dtls* dtls) {
memset(dtls, 0, sizeof(struct capwap_dtls)); 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) { int capwap_crypt_sendto(struct capwap_dtls* dtls, void* buffer, int size) {
ASSERT(sock >= 0); ASSERT(dtls != NULL);
ASSERT(dtls->sock >= 0);
ASSERT(buffer != NULL); ASSERT(buffer != NULL);
ASSERT(size > 0); ASSERT(size > 0);
ASSERT(sendtoaddr != NULL);
if (!dtls || !dtls->enable) { if (!dtls->enable) {
return capwap_sendto(sock, buffer, size, sendfromaddr, sendtoaddr); return capwap_sendto(dtls->sock, buffer, size, &dtls->peeraddr);
} }
/* Valid DTLS status */ /* Valid DTLS status */
@ -493,12 +503,12 @@ int capwap_crypt_sendto(struct capwap_dtls* dtls, int sock, void* buffer, int si
} }
/* */ /* */
int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr) { int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, struct capwap_list* fragmentlist) {
struct capwap_list_item* item; struct capwap_list_item* item;
ASSERT(sock >= 0); ASSERT(dtls != NULL);
ASSERT(dtls->sock >= 0);
ASSERT(fragmentlist != NULL); ASSERT(fragmentlist != NULL);
ASSERT(sendtoaddr != NULL);
item = fragmentlist->first; item = fragmentlist->first;
while (item) { while (item) {
@ -506,7 +516,7 @@ int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, int sock, struc
ASSERT(fragmentpacket != NULL); ASSERT(fragmentpacket != NULL);
ASSERT(fragmentpacket->offset > 0); ASSERT(fragmentpacket->offset > 0);
if (!capwap_crypt_sendto(dtls, sock, fragmentpacket->buffer, fragmentpacket->offset, sendfromaddr, sendtoaddr)) { if (!capwap_crypt_sendto(dtls, fragmentpacket->buffer, fragmentpacket->offset)) {
return 0; return 0;
} }
@ -536,7 +546,7 @@ int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size,
if (!plainbuffer) { if (!plainbuffer) {
clone = capwap_clone(encrybuffer, size); clone = capwap_clone(encrybuffer, size);
} }
dtls->buffer = (clone ? clone : encrybuffer); dtls->buffer = (clone ? clone : encrybuffer);
dtls->length = size; dtls->length = size;

View File

@ -2,6 +2,7 @@
#define __CAPWAP_DTLS_HEADER__ #define __CAPWAP_DTLS_HEADER__
#include "capwap_list.h" #include "capwap_list.h"
#include "capwap_network.h"
#define CAPWAP_DTLS_CLIENT 0 #define CAPWAP_DTLS_CLIENT 0
#define CAPWAP_DTLS_SERVER 1 #define CAPWAP_DTLS_SERVER 1
@ -20,16 +21,12 @@
#define CAPWAP_HANDSHAKE_CONTINUE 0 #define CAPWAP_HANDSHAKE_CONTINUE 0
#define CAPWAP_HANDSHAKE_COMPLETE 1 #define CAPWAP_HANDSHAKE_COMPLETE 1
#define CAPWAP_DTLS_CONTROL_SESSION 0
#define CAPWAP_DTLS_DATA_SESSION 1
#define CAPWAP_ERROR_AGAIN 0 #define CAPWAP_ERROR_AGAIN 0
#define CAPWAP_ERROR_SHUTDOWN -1 #define CAPWAP_ERROR_SHUTDOWN -1
#define CAPWAP_ERROR_CLOSE -2 #define CAPWAP_ERROR_CLOSE -2
/* */ /* */
struct capwap_dtls; struct capwap_dtls;
typedef int(*capwap_bio_send)(struct capwap_dtls* dtls, char* buffer, int length, void* param);
/* */ /* */
struct capwap_dtls_context { struct capwap_dtls_context {
@ -51,15 +48,15 @@ struct capwap_dtls_context {
struct capwap_dtls { struct capwap_dtls {
int enable; int enable;
int action; int action;
int session;
/* */
void* sslsession; void* sslsession;
struct capwap_dtls_context* dtlscontext; struct capwap_dtls_context* dtlscontext;
/* Send callback */ /* */
struct sockaddr_storage peeraddr; int sock;
capwap_bio_send send; union sockaddr_capwap localaddr;
void* sendparam; union sockaddr_capwap peeraddr;
/* Buffer read */ /* Buffer read */
void* buffer; void* buffer;
@ -94,14 +91,15 @@ void capwap_crypt_free();
int capwap_crypt_createcontext(struct capwap_dtls_context* dtlscontext, struct capwap_dtls_param* param); int capwap_crypt_createcontext(struct capwap_dtls_context* dtlscontext, struct capwap_dtls_param* param);
void capwap_crypt_freecontext(struct capwap_dtls_context* dtlscontext); 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_setconnection(struct capwap_dtls* dtls, int sock, union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr);
int capwap_crypt_createsession(struct capwap_dtls* dtls, struct capwap_dtls_context* dtlscontext);
void capwap_crypt_freesession(struct capwap_dtls* dtls); void capwap_crypt_freesession(struct capwap_dtls* dtls);
int capwap_crypt_open(struct capwap_dtls* dtls, struct sockaddr_storage* peeraddr); int capwap_crypt_open(struct capwap_dtls* dtls);
void capwap_crypt_close(struct capwap_dtls* dtls); void capwap_crypt_close(struct capwap_dtls* dtls);
int capwap_crypt_sendto(struct capwap_dtls* dtls, int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_crypt_sendto(struct capwap_dtls* dtls, void* buffer, int size);
int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, struct capwap_list* fragmentlist);
int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size, void* plainbuffer, int maxsize); int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size, void* plainbuffer, int maxsize);
int capwap_crypt_has_dtls_clienthello(void* buffer, int buffersize); int capwap_crypt_has_dtls_clienthello(void* buffer, int buffersize);

View File

@ -172,8 +172,9 @@ void* capwap_get_message_element_data(struct capwap_parsed_packet* packet, uint1
} }
/* */ /* */
int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, struct capwap_parsed_packet* packet) { int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap_parsed_packet* packet) {
unsigned short binding; unsigned short binding;
unsigned short bodylength;
ASSERT(rxmngpacket != NULL); ASSERT(rxmngpacket != NULL);
ASSERT(packet != NULL); ASSERT(packet != NULL);
@ -181,7 +182,6 @@ int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap
/* */ /* */
memset(packet, 0, sizeof(struct capwap_parsed_packet)); memset(packet, 0, sizeof(struct capwap_parsed_packet));
packet->rxmngpacket = rxmngpacket; packet->rxmngpacket = rxmngpacket;
packet->connection = connection;
packet->messages = capwap_list_create(); packet->messages = capwap_list_create();
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
@ -189,179 +189,115 @@ int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap
/* Position reader to capwap body */ /* Position reader to capwap body */
memcpy(&rxmngpacket->readpos, &rxmngpacket->readbodypos, sizeof(struct read_block_from_pos)); memcpy(&rxmngpacket->readpos, &rxmngpacket->readbodypos, sizeof(struct read_block_from_pos));
if (rxmngpacket->isctrlpacket) { /* */
unsigned short bodylength = rxmngpacket->ctrlmsg.length - CAPWAP_CONTROL_MESSAGE_MIN_LENGTH; bodylength = rxmngpacket->ctrlmsg.length - CAPWAP_CONTROL_MESSAGE_MIN_LENGTH;
while (bodylength > 0) { while (bodylength > 0) {
uint16_t type;
uint16_t msglength;
int category;
struct capwap_list_item* itemlist;
struct capwap_message_element_itemlist* messageelement;
struct capwap_message_elements_ops* read_ops;
/* Get type and length */
rxmngpacket->readerpacketallowed = sizeof(struct capwap_message_element);
if (rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &type) != sizeof(uint16_t)) {
return INVALID_MESSAGE_ELEMENT;
}
/* Check type */
if (!IS_VALID_MESSAGE_ELEMENTS(type)) {
return UNRECOGNIZED_MESSAGE_ELEMENT;
}
/* Check binding */
if (IS_80211_MESSAGE_ELEMENTS(type) && (binding != CAPWAP_WIRELESS_BINDING_IEEE80211)) {
return UNRECOGNIZED_MESSAGE_ELEMENT;
}
if (rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &msglength) != sizeof(uint16_t)) {
return INVALID_MESSAGE_ELEMENT;
}
/* Check length */
if (msglength > bodylength) {
return INVALID_MESSAGE_ELEMENT;
}
/* Reader function */
read_ops = capwap_get_message_element_ops(type);
if (!read_ops) {
return INVALID_MESSAGE_ELEMENT;
}
/* Allowed to parsing only the size of message element */
rxmngpacket->readerpacketallowed = msglength;
/* */
itemlist = capwap_get_message_element(packet, type);
category = capwap_get_message_element_category(type);
if (category == CAPWAP_MESSAGE_ELEMENT_SINGLE) {
/* Check for multiple message element */
if (itemlist) {
return INVALID_MESSAGE_ELEMENT;
}
/* Create new message element */
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist));
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
messageelement->type = type;
messageelement->category = CAPWAP_MESSAGE_ELEMENT_SINGLE;
messageelement->data = read_ops->parsing_message_element((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->read_ops);
if (!messageelement->data) {
capwap_itemlist_free(itemlist);
return INVALID_MESSAGE_ELEMENT;
}
/* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist);
} else if (category == CAPWAP_MESSAGE_ELEMENT_ARRAY) {
void* datamsgelement;
struct capwap_array* arraymessageelement;
if (itemlist) {
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
arraymessageelement = (struct capwap_array*)messageelement->data;
} else {
arraymessageelement = capwap_array_create(sizeof(void*), 0, 0);
/* */
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist));
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
messageelement->type = type;
messageelement->category = CAPWAP_MESSAGE_ELEMENT_ARRAY;
messageelement->data = (void*)arraymessageelement;
/* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist);
}
/* Get message element */
datamsgelement = read_ops->parsing_message_element((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->read_ops);
if (!datamsgelement) {
return INVALID_MESSAGE_ELEMENT;
}
/* */
memcpy(capwap_array_get_item_pointer(arraymessageelement, arraymessageelement->count), &datamsgelement, sizeof(void*));
}
/* Check if read all data of message element */
if (rxmngpacket->readerpacketallowed) {
return INVALID_MESSAGE_ELEMENT;
}
/* */
bodylength -= (msglength + sizeof(struct capwap_message_element));
}
} else if (IS_FLAG_K_HEADER(rxmngpacket->header)) {
uint16_t type; uint16_t type;
uint16_t msglength; uint16_t msglength;
int category;
struct capwap_list_item* itemlist; struct capwap_list_item* itemlist;
struct capwap_message_element_itemlist* messageelement; struct capwap_message_element_itemlist* messageelement;
struct capwap_message_elements_ops* read_ops; struct capwap_message_elements_ops* read_ops;
unsigned short bodylength = rxmngpacket->datamsg.length - CAPWAP_DATA_MESSAGE_KEEPALIVE_MIN_LENGTH;
/* Get type and length */ /* Get type and length */
rxmngpacket->readerpacketallowed = sizeof(struct capwap_message_element); rxmngpacket->readerpacketallowed = sizeof(struct capwap_message_element);
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &type); if (rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &type) != sizeof(uint16_t)) {
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &msglength); return INVALID_MESSAGE_ELEMENT;
}
/* Check type */
if (!IS_VALID_MESSAGE_ELEMENTS(type)) {
return UNRECOGNIZED_MESSAGE_ELEMENT;
}
/* Check binding */
if (IS_80211_MESSAGE_ELEMENTS(type) && (binding != CAPWAP_WIRELESS_BINDING_IEEE80211)) {
return UNRECOGNIZED_MESSAGE_ELEMENT;
}
if (rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &msglength) != sizeof(uint16_t)) {
return INVALID_MESSAGE_ELEMENT;
}
/* Check length */ /* Check length */
if ((msglength + sizeof(struct capwap_message_element)) != bodylength) { if (msglength > bodylength) {
return INVALID_MESSAGE_ELEMENT;
}
/* Reader function */
read_ops = capwap_get_message_element_ops(type);
if (!read_ops) {
return INVALID_MESSAGE_ELEMENT; return INVALID_MESSAGE_ELEMENT;
} }
/* Allowed to parsing only the size of message element */ /* Allowed to parsing only the size of message element */
rxmngpacket->readerpacketallowed = msglength; rxmngpacket->readerpacketallowed = msglength;
if (type != CAPWAP_ELEMENT_SESSIONID) {
return UNRECOGNIZED_MESSAGE_ELEMENT; /* */
itemlist = capwap_get_message_element(packet, type);
category = capwap_get_message_element_category(type);
if (category == CAPWAP_MESSAGE_ELEMENT_SINGLE) {
/* Check for multiple message element */
if (itemlist) {
return INVALID_MESSAGE_ELEMENT;
}
/* Create new message element */
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist));
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
messageelement->type = type;
messageelement->category = CAPWAP_MESSAGE_ELEMENT_SINGLE;
messageelement->data = read_ops->parsing_message_element((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->read_ops);
if (!messageelement->data) {
capwap_itemlist_free(itemlist);
return INVALID_MESSAGE_ELEMENT;
}
/* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist);
} else if (category == CAPWAP_MESSAGE_ELEMENT_ARRAY) {
void* datamsgelement;
struct capwap_array* arraymessageelement;
if (itemlist) {
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
arraymessageelement = (struct capwap_array*)messageelement->data;
} else {
arraymessageelement = capwap_array_create(sizeof(void*), 0, 0);
/* */
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist));
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
messageelement->type = type;
messageelement->category = CAPWAP_MESSAGE_ELEMENT_ARRAY;
messageelement->data = (void*)arraymessageelement;
/* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist);
}
/* Get message element */
datamsgelement = read_ops->parsing_message_element((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->read_ops);
if (!datamsgelement) {
return INVALID_MESSAGE_ELEMENT;
}
/* */
memcpy(capwap_array_get_item_pointer(arraymessageelement, arraymessageelement->count), &datamsgelement, sizeof(void*));
} }
/* Retrieve session id */ /* Check if read all data of message element */
read_ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_SESSIONID); if (rxmngpacket->readerpacketallowed) {
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist)); return INVALID_MESSAGE_ELEMENT;
messageelement = (struct capwap_message_element_itemlist*)itemlist->item;
messageelement->type = CAPWAP_ELEMENT_SESSIONID;
messageelement->category = CAPWAP_MESSAGE_ELEMENT_SINGLE;
messageelement->data = read_ops->parsing_message_element((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->read_ops);
if (!messageelement->data) {
capwap_itemlist_free(itemlist);
return INVALID_MESSAGE_ELEMENT;
} }
/* */ /* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist); bodylength -= (msglength + sizeof(struct capwap_message_element));
} }
return PARSING_COMPLETE; return PARSING_COMPLETE;
} }
/* */
int capwap_packet_getdata(struct capwap_packet_rxmng* rxmngpacket, uint8_t* buffer, int maxlength) {
int result;
ASSERT(rxmngpacket != NULL);
ASSERT(buffer != NULL);
ASSERT(maxlength > 0);
/* Get only data packet */
if (rxmngpacket->isctrlpacket || IS_FLAG_K_HEADER(rxmngpacket->header)) {
return -1;
} else if (rxmngpacket->packetlength > maxlength) {
return -1;
}
/* Get data packet */
rxmngpacket->readerpacketallowed = rxmngpacket->packetlength;
result = rxmngpacket->read_ops.read_block((capwap_message_elements_handle)rxmngpacket, buffer, rxmngpacket->packetlength);
if (result != rxmngpacket->packetlength) {
return -1;
}
return result;
}
/* */ /* */
int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct capwap_array* returnedmessage) { int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct capwap_array* returnedmessage) {
unsigned short binding; unsigned short binding;
@ -372,350 +308,335 @@ int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct ca
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket) { switch (packet->rxmngpacket->ctrlmsg.type) {
switch (packet->rxmngpacket->ctrlmsg.type) { case CAPWAP_DISCOVERY_REQUEST: {
case CAPWAP_DISCOVERY_REQUEST: { if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DISCOVERYTYPE) &&
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DISCOVERYTYPE) && capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) && capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) && capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) && capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE)) {
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) { if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0; return 0;
} }
} } else {
break;
}
case CAPWAP_DISCOVERY_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0; return 0;
} }
break;
} }
case CAPWAP_JOIN_REQUEST: { break;
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCATION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_SESSIONID) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ECNSUPPORT) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_JOIN_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ECNSUPPORT) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6)) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0;
}
break;
}
case CAPWAP_CONFIGURATION_STATUS_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOADMSTATE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_STATISTICSTIMER) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPREBOOTSTAT)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_CONFIGURATION_STATUS_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_TIMERS) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_IDLETIMEOUT) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFALLBACK) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_ACIPV4LIST) || capwap_get_message_element(packet, CAPWAP_ELEMENT_ACIPV6LIST))) {
return 0;
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0;
}
break;
}
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAMEPRIORITY) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACTIMESTAMP) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_ADDMACACL) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_TIMERS) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETEMACACL) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_IDLETIMEOUT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCATION) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOADMSTATE) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_STATISTICSTIMER) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFALLBACK) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPNAME) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPSTATICIPADDRESS) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_IMAGEIDENTIFIER) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_VENDORPAYLOAD)) {
return 0;
}
break;
}
case CAPWAP_CONFIGURATION_UPDATE_RESPONSE: {
return 0;
}
case CAPWAP_WTP_EVENT_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DUPLICATEIPV4) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DUPLICATEIPV6) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPRADIOSTAT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPREBOOTSTAT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETESTATION) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_VENDORPAYLOAD)) {
return 0;
}
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
return 0;
}
case CAPWAP_CHANGE_STATE_EVENT_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOOPRSTATE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
return 0;
}
case CAPWAP_ECHO_REQUEST: {
return 0;
}
case CAPWAP_ECHO_RESPONSE: {
return 0;
}
case CAPWAP_IMAGE_DATA_REQUEST: {
return 0;
}
case CAPWAP_IMAGE_DATA_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_RESET_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_IMAGEIDENTIFIER)) {
return 0;
}
break;
}
case CAPWAP_RESET_RESPONSE: {
return 0;
}
case CAPWAP_PRIMARY_DISCOVERY_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DISCOVERYTYPE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_PRIMARY_DISCOVERY_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0;
}
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
return 0;
}
case CAPWAP_CLEAR_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ADDSTATION)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_STATION)) {
return 0;
}
} else {
return 0;
}
} else if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETESTATION)) {
return 0;
}
break;
}
case CAPWAP_STATION_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_ADD_WLAN) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_UPDATE_WLAN) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_DELETE_WLAN)) {
return 0;
}
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
} }
} else {
/* Keep alive data message require session id */ case CAPWAP_DISCOVERY_RESPONSE: {
if (IS_FLAG_K_HEADER(packet->rxmngpacket->header)) { if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_SESSIONID)) { capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0; return 0;
} }
} else {
/* Validate Radio ID */ break;
uint8_t radioid = GET_RID_HEADER(packet->rxmngpacket->header); }
if (IS_VALID_RADIOID(radioid)) {
case CAPWAP_JOIN_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCATION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_SESSIONID) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ECNSUPPORT) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_JOIN_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ECNSUPPORT) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6)) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCALIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0; return 0;
} }
break;
}
case CAPWAP_CONFIGURATION_STATUS_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOADMSTATE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_STATISTICSTIMER) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPREBOOTSTAT)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_CONFIGURATION_STATUS_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_TIMERS) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_IDLETIMEOUT) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFALLBACK) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_ACIPV4LIST) || capwap_get_message_element(packet, CAPWAP_ELEMENT_ACIPV6LIST))) {
return 0;
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0;
}
break;
}
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAMEPRIORITY) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACTIMESTAMP) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_ADDMACACL) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_TIMERS) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETEMACACL) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_IDLETIMEOUT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_LOCATION) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOADMSTATE) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_STATISTICSTIMER) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFALLBACK) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPNAME) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPSTATICIPADDRESS) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_IMAGEIDENTIFIER) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_VENDORPAYLOAD)) {
return 0;
}
break;
}
case CAPWAP_CONFIGURATION_UPDATE_RESPONSE: {
return 0;
}
case CAPWAP_WTP_EVENT_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DECRYPTERRORREPORTPERIOD) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DUPLICATEIPV4) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DUPLICATEIPV6) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPRADIOSTAT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPREBOOTSTAT) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETESTATION) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_VENDORPAYLOAD)) {
return 0;
}
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
return 0;
}
case CAPWAP_CHANGE_STATE_EVENT_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RADIOOPRSTATE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
return 0;
}
case CAPWAP_ECHO_REQUEST: {
return 0;
}
case CAPWAP_ECHO_RESPONSE: {
return 0;
}
case CAPWAP_IMAGE_DATA_REQUEST: {
return 0;
}
case CAPWAP_IMAGE_DATA_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_RESET_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_IMAGEIDENTIFIER)) {
return 0;
}
break;
}
case CAPWAP_RESET_RESPONSE: {
return 0;
}
case CAPWAP_PRIMARY_DISCOVERY_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DISCOVERYTYPE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPBOARDDATA) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPDESCRIPTOR) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPFRAMETUNNELMODE) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_WTPMACTYPE)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
break;
}
case CAPWAP_PRIMARY_DISCOVERY_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ACDESCRIPTION) &&
capwap_get_message_element(packet, CAPWAP_ELEMENT_ACNAME) &&
(capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV4) || capwap_get_message_element(packet, CAPWAP_ELEMENT_CONTROLIPV6))) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
} else {
return 0;
}
}
/* Check if packet contains Result Code with Error Message */
resultcode = (struct capwap_resultcode_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_RESULTCODE);
if (resultcode && !CAPWAP_RESULTCODE_OK(resultcode->code)) {
return 0;
}
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
return 0;
}
case CAPWAP_CLEAR_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_ADDSTATION)) {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_STATION)) {
return 0;
}
} else {
return 0;
}
} else if (capwap_get_message_element(packet, CAPWAP_ELEMENT_DELETESTATION)) {
return 0;
}
break;
}
case CAPWAP_STATION_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_ADD_WLAN) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_UPDATE_WLAN) ||
capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_DELETE_WLAN)) {
return 0;
}
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE: {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_RESULTCODE)) {
return 0;
}
break;
} }
} }
@ -761,7 +682,4 @@ void capwap_free_parsed_packet(struct capwap_parsed_packet* packet) {
capwap_list_free(packet->messages); capwap_list_free(packet->messages);
packet->messages = NULL; packet->messages = NULL;
} }
/* */
packet->connection = NULL;
} }

View File

@ -131,7 +131,6 @@ struct capwap_message_element_itemlist {
struct capwap_parsed_packet { struct capwap_parsed_packet {
struct capwap_packet_rxmng* rxmngpacket; struct capwap_packet_rxmng* rxmngpacket;
struct capwap_connection* connection;
struct capwap_list* messages; struct capwap_list* messages;
}; };
@ -140,13 +139,11 @@ struct capwap_parsed_packet {
#define UNRECOGNIZED_MESSAGE_ELEMENT 1 #define UNRECOGNIZED_MESSAGE_ELEMENT 1
#define INVALID_MESSAGE_ELEMENT 2 #define INVALID_MESSAGE_ELEMENT 2
int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, struct capwap_parsed_packet* packet); int capwap_parsing_packet(struct capwap_packet_rxmng* rxmngpacket, struct capwap_parsed_packet* packet);
int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct capwap_array* returnedmessage); int capwap_validate_parsed_packet(struct capwap_parsed_packet* packet, struct capwap_array* returnedmessage);
void capwap_free_parsed_packet(struct capwap_parsed_packet* packet); void capwap_free_parsed_packet(struct capwap_parsed_packet* packet);
struct capwap_list_item* capwap_get_message_element(struct capwap_parsed_packet* packet, uint16_t type); struct capwap_list_item* capwap_get_message_element(struct capwap_parsed_packet* packet, uint16_t type);
void* capwap_get_message_element_data(struct capwap_parsed_packet* packet, uint16_t type); void* capwap_get_message_element_data(struct capwap_parsed_packet* packet, uint16_t type);
int capwap_packet_getdata(struct capwap_packet_rxmng* rxmngpacket, uint8_t* buffer, int maxlength);
#endif /* __CAPWAP_ELEMENT_HEADER__ */ #endif /* __CAPWAP_ELEMENT_HEADER__ */

File diff suppressed because it is too large Load Diff

View File

@ -12,87 +12,62 @@
#define CAPWAP_MACADDRESS_EUI48_BUFFER 18 #define CAPWAP_MACADDRESS_EUI48_BUFFER 18
#define CAPWAP_MACADDRESS_EUI64_BUFFER 24 #define CAPWAP_MACADDRESS_EUI64_BUFFER 24
/* Helper */
#define CAPWAP_GET_NETWORK_PORT(address) ntohs((((address)->ss_family == AF_INET) ? ((struct sockaddr_in*)(address))->sin_port : ((struct sockaddr_in6*)(address))->sin6_port))
#define CAPWAP_SET_NETWORK_PORT(address, port) if ((address)->ss_family == AF_INET) { \
((struct sockaddr_in*)(address))->sin_port = htons(port); \
} else if ((address)->ss_family == AF_INET6) { \
((struct sockaddr_in6*)(address))->sin6_port = htons(port); \
}
/* */ /* */
#define CAPWAP_MAX_SOCKETS 4 union sockaddr_capwap {
#define CAPWAP_SOCKET_IPV4_UDP 0 struct sockaddr sa;
#define CAPWAP_SOCKET_IPV4_UDPLITE 1 struct sockaddr_in sin;
#define CAPWAP_SOCKET_IPV6_UDP 2 struct sockaddr_in6 sin6;
#define CAPWAP_SOCKET_IPV6_UDPLITE 3 struct sockaddr_storage ss;
};
/* Helper */
#define CAPWAP_GET_NETWORK_PORT(addr) ntohs((((addr)->ss.ss_family == AF_INET) ? (addr)->sin.sin_port : (addr)->sin6.sin6_port))
#define CAPWAP_SET_NETWORK_PORT(addr, port) if ((addr)->ss.ss_family == AF_INET) { \
(addr)->sin.sin_port = htons(port); \
} else if ((addr)->ss.ss_family == AF_INET6) { \
(addr)->sin6.sin6_port = htons(port); \
}
#define CAPWAP_COPY_NETWORK_PORT(addr1, addr2) if ((addr1)->ss.ss_family == (addr2)->ss.ss_family) { \
if ((addr1)->ss.ss_family == AF_INET) { \
(addr1)->sin.sin_port = (addr2)->sin.sin_port; \
} else if ((addr1)->ss.ss_family == AF_INET6) { \
(addr1)->sin6.sin6_port = (addr2)->sin6.sin6_port; \
} \
}
/* */ /* */
#define CAPWAP_RECV_ERROR_SOCKET -1 #define CAPWAP_RECV_ERROR_SOCKET -1
#define CAPWAP_RECV_ERROR_TIMEOUT -2 #define CAPWAP_RECV_ERROR_TIMEOUT -2
#define CAPWAP_RECV_ERROR_INTR -3 #define CAPWAP_RECV_ERROR_INTR -3
/* Socket Flags */
#define CAPWAP_IPV6ONLY_FLAG 0x00000001
/* Network struct */ /* Network struct */
struct capwap_network { struct capwap_network {
int sock_family; /* Address family used by the server. */ union sockaddr_capwap localaddr;
unsigned short bind_sock_ctrl_port; /* Port number to listen control protocol. */ char bindiface[IFNAMSIZ];
char bind_interface[IFNAMSIZ]; int socket;
int sock_ctrl[CAPWAP_MAX_SOCKETS];
int bind_ctrl_flags;
int sock_data[CAPWAP_MAX_SOCKETS];
int bind_data_flags;
};
#define CAPWAP_SOCKET_UDP 0
#define CAPWAP_SOCKET_UDPLITE 1
/* Network socket */
struct capwap_socket {
int type;
int family;
int socket[2];
int isctrlsocket;
};
/* Network connection info */
struct capwap_connection {
struct capwap_socket socket;
struct sockaddr_storage localaddr;
struct sockaddr_storage remoteaddr;
}; };
void capwap_network_init(struct capwap_network* net); void capwap_network_init(struct capwap_network* net);
int capwap_network_set_pollfd(struct capwap_network* net, struct pollfd* fds, int fdscount); int capwap_network_set_pollfd(struct capwap_network* net, struct pollfd* fds, int fdscount);
void capwap_interface_list(struct capwap_network* net, struct capwap_list* list); void capwap_interface_list(struct capwap_network* net, struct capwap_list* list);
int capwap_get_macaddress_from_interface(const char* interface, char* macaddress); int capwap_get_macaddress_from_interface(const char* interface, char* macaddress);
int capwap_network_get_localaddress(union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr, char* iface);
#define CAPWAP_DATA_SOCKET 0
#define CAPWAP_CTRL_SOCKET 1
int capwap_get_socket(struct capwap_network* net, int socketfamily, int socketprotocol, int isctrlsocket);
void capwap_get_network_socket(struct capwap_network* net, struct capwap_socket* sock, int fd);
int capwap_bind_sockets(struct capwap_network* net); int capwap_bind_sockets(struct capwap_network* net);
void capwap_close_sockets(struct capwap_network* net); void capwap_close_sockets(struct capwap_network* net);
int capwap_compare_ip(struct sockaddr_storage* addr1, struct sockaddr_storage* addr2); int capwap_ipv4_mapped_ipv6(union sockaddr_capwap* addr);
int capwap_compare_ip(union sockaddr_capwap* addr1, union sockaddr_capwap* addr2);
int capwap_sendto(int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_sendto(int sock, void* buffer, int size, union sockaddr_capwap* toaddr);
int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr); int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, union sockaddr_capwap* toaddr);
int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeout* timeout); int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeout* timeout);
int capwap_recvfrom_fd(int fd, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr); int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr);
int capwap_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct capwap_timeout* timeout);
int capwap_ipv4_mapped_ipv6(struct sockaddr_storage* source, struct sockaddr_storage* dest); int capwap_address_from_string(const char* ip, union sockaddr_capwap* sockaddr);
int capwap_address_from_string(const char* ip, struct sockaddr_storage* address);
int capwap_get_localaddress_by_remoteaddress(struct sockaddr_storage* local, struct sockaddr_storage* remote, char* oif, int ipv6dualstack);
char* capwap_printf_macaddress(char* buffer, const uint8_t* macaddress, int type); char* capwap_printf_macaddress(char* buffer, const uint8_t* macaddress, int type);
int capwap_scanf_macaddress(uint8_t* macaddress, const char* buffer, int type); int capwap_scanf_macaddress(uint8_t* macaddress, const char* buffer, int type);

View File

@ -4,10 +4,9 @@
#include "capwap_dfa.h" #include "capwap_dfa.h"
#include "capwap_list.h" #include "capwap_list.h"
#include "capwap_array.h" #include "capwap_array.h"
#include "md5.h"
/* Check valid packet */ /* Check valid packet */
int capwap_sanity_check(int isctrlsocket, int state, void* buffer, int buffersize, int dtlsctrlenable, int dtlsdataenable) { int capwap_sanity_check(int state, void* buffer, int buffersize, int dtlsenable) {
struct capwap_preamble* preamble; struct capwap_preamble* preamble;
ASSERT(buffer != NULL); ASSERT(buffer != NULL);
@ -18,43 +17,28 @@ int capwap_sanity_check(int isctrlsocket, int state, void* buffer, int buffersiz
return CAPWAP_WRONG_PACKET; return CAPWAP_WRONG_PACKET;
} }
if (isctrlsocket) { if (dtlsenable) {
if (dtlsctrlenable) { if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) {
if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) { if (state == CAPWAP_DISCOVERY_STATE) {
if (state == CAPWAP_DISCOVERY_STATE) { return CAPWAP_WRONG_PACKET;
}
return CAPWAP_DTLS_PACKET;
} else if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && (buffersize >= sizeof(struct capwap_header))) {
struct capwap_header* header = (struct capwap_header*)preamble;
if (buffersize >= GET_HLEN_HEADER(header) * 4) {
if ((state != CAPWAP_DISCOVERY_STATE) && (state != CAPWAP_UNDEF_STATE)) {
return CAPWAP_WRONG_PACKET; return CAPWAP_WRONG_PACKET;
} }
return CAPWAP_DTLS_PACKET; return CAPWAP_PLAIN_PACKET;
} else if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && (buffersize >= sizeof(struct capwap_header))) {
struct capwap_header* header = (struct capwap_header*)preamble;
if (buffersize >= GET_HLEN_HEADER(header) * 4) {
if ((state != CAPWAP_DISCOVERY_STATE) && (state != CAPWAP_UNDEF_STATE)) {
return CAPWAP_WRONG_PACKET;
}
return CAPWAP_PLAIN_PACKET;
}
}
} else {
if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && (buffersize >= sizeof(struct capwap_header))) {
struct capwap_header* header = (struct capwap_header*)preamble;
if (buffersize >= GET_HLEN_HEADER(header) * 4) {
return CAPWAP_PLAIN_PACKET;
}
} }
} }
} else { } else {
if (dtlsdataenable) { if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && (buffersize >= sizeof(struct capwap_header))) {
if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) { struct capwap_header* header = (struct capwap_header*)preamble;
return CAPWAP_DTLS_PACKET; if (buffersize >= GET_HLEN_HEADER(header) * 4) {
} return CAPWAP_PLAIN_PACKET;
} else {
if ((preamble->type == CAPWAP_PREAMBLE_HEADER) && (buffersize >= sizeof(struct capwap_header))) {
struct capwap_header* header = (struct capwap_header*)preamble;
if (buffersize >= GET_HLEN_HEADER(header) * 4) {
return CAPWAP_PLAIN_PACKET;
}
} }
} }
} }
@ -86,79 +70,13 @@ int capwap_is_request_type(unsigned long type) {
return 0; return 0;
} }
/* Retrieve packet digest */
void capwap_get_packet_digest(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16]) {
MD5_CTX mdContext;
struct capwap_list_item* item;
struct capwap_fragment_packet_item* packet;
ASSERT(rxmngpacket != NULL);
ASSERT(rxmngpacket->packetlength > 0);
ASSERT(connection != NULL);
MD5Init(&mdContext);
/* Address */
if ((connection->localaddr.ss_family == AF_INET) && ((connection->remoteaddr.ss_family == AF_INET))) {
struct sockaddr_in* localaddr_in = (struct sockaddr_in*)&connection->localaddr;
struct sockaddr_in* remoteaddr_in = (struct sockaddr_in*)&connection->remoteaddr;
MD5Update(&mdContext, (unsigned char*)&localaddr_in->sin_addr.s_addr, sizeof(unsigned long));
MD5Update(&mdContext, (unsigned char*)&localaddr_in->sin_port, sizeof(unsigned short));
MD5Update(&mdContext, (unsigned char*)&remoteaddr_in->sin_addr.s_addr, sizeof(unsigned long));
MD5Update(&mdContext, (unsigned char*)&remoteaddr_in->sin_port, sizeof(unsigned short));
} else if ((connection->localaddr.ss_family == AF_INET6) && ((connection->remoteaddr.ss_family == AF_INET6))) {
struct sockaddr_in6* localaddr_in6 = (struct sockaddr_in6*)&connection->localaddr;
struct sockaddr_in6* remoteaddr_in6 = (struct sockaddr_in6*)&connection->remoteaddr;
MD5Update(&mdContext, (unsigned char*)&localaddr_in6->sin6_addr, sizeof(struct in6_addr));
MD5Update(&mdContext, (unsigned char*)&localaddr_in6->sin6_port, sizeof(unsigned short));
MD5Update(&mdContext, (unsigned char*)&remoteaddr_in6->sin6_addr, sizeof(struct in6_addr));
MD5Update(&mdContext, (unsigned char*)&remoteaddr_in6->sin6_port, sizeof(unsigned short));
}
/* Packet */
item = rxmngpacket->fragmentlist->first;
while (item) {
packet = (struct capwap_fragment_packet_item*)item->item;
MD5Update(&mdContext, (unsigned char*)packet->buffer, packet->offset);
item = item->next;
}
MD5Final(&mdContext);
memcpy(&packetdigest[0], &mdContext.digest[0], 16);
}
/* Verify duplicate packet */
int capwap_recv_retrasmitted_request(struct capwap_dtls* dtls, struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16], struct capwap_list* txfragmentpacket) {
unsigned char recvpacketdigest[16];
ASSERT(rxmngpacket != NULL);
ASSERT(connection != NULL);
ASSERT(txfragmentpacket != NULL);
/* Check packet digest */
capwap_get_packet_digest(rxmngpacket, connection, recvpacketdigest);
if (!memcmp(&recvpacketdigest[0], &packetdigest[0], 16)) {
/* Retransmit response */
if (!capwap_crypt_sendto_fragmentpacket(dtls, connection->socket.socket[connection->socket.type], txfragmentpacket, &connection->localaddr, &connection->remoteaddr)) {
capwap_logging_debug("Warning: error to resend response packet");
}
return 1;
}
return 0;
}
/* Check valid message type */ /* Check valid message type */
int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket) { int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket) {
unsigned short lengthpayload; unsigned short lengthpayload;
ASSERT(rxmngpacket != NULL); ASSERT(rxmngpacket != NULL);
if (rxmngpacket->isctrlpacket && rxmngpacket->fragmentlist->first) { if (rxmngpacket->fragmentlist->first) {
struct capwap_fragment_packet_item* packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item; struct capwap_fragment_packet_item* packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item;
struct capwap_header* header = (struct capwap_header*)packet->buffer; struct capwap_header* header = (struct capwap_header*)packet->buffer;
unsigned short binding = GET_WBID_HEADER(rxmngpacket->header); unsigned short binding = GET_WBID_HEADER(rxmngpacket->header);
@ -176,8 +94,6 @@ int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket) {
return INVALID_REQUEST_MESSAGE_TYPE; return INVALID_REQUEST_MESSAGE_TYPE;
} }
} }
} else if (!rxmngpacket->isctrlpacket && rxmngpacket->fragmentlist->first) {
return VALID_MESSAGE_TYPE;
} }
return INVALID_MESSAGE_TYPE; return INVALID_MESSAGE_TYPE;
@ -420,11 +336,7 @@ static int capwap_fragment_write_block_from_pos(struct capwap_packet_txmng* txmn
unsigned short oldoffset = fragmentpacket->offset; unsigned short oldoffset = fragmentpacket->offset;
fragmentpacket->offset = available + packetpos; fragmentpacket->offset = available + packetpos;
if (txmngpacket->isctrlpacket) { txmngpacket->ctrlmsg->length = htons(ntohs(txmngpacket->ctrlmsg->length) + (fragmentpacket->offset - oldoffset));
txmngpacket->ctrlmsg->length = htons(ntohs(txmngpacket->ctrlmsg->length) + (fragmentpacket->offset - oldoffset));
} else if (IS_FLAG_K_HEADER(txmngpacket->header)) {
txmngpacket->datamsg->length = htons(ntohs(txmngpacket->datamsg->length) + (fragmentpacket->offset - oldoffset));
}
} }
} }
@ -560,8 +472,6 @@ struct capwap_packet_txmng* capwap_packet_txmng_create_ctrl_message(struct capwa
ASSERT((fragmentpacket->offset + sizeof(struct capwap_control_message)) < fragmentpacket->size); ASSERT((fragmentpacket->offset + sizeof(struct capwap_control_message)) < fragmentpacket->size);
/* Create message */ /* Create message */
txmngpacket->isctrlpacket = 1;
txmngpacket->ctrlmsg = (struct capwap_control_message*)&fragmentpacket->buffer[fragmentpacket->offset]; txmngpacket->ctrlmsg = (struct capwap_control_message*)&fragmentpacket->buffer[fragmentpacket->offset];
txmngpacket->ctrlmsg->type = htonl(type); txmngpacket->ctrlmsg->type = htonl(type);
txmngpacket->ctrlmsg->seq = seq; txmngpacket->ctrlmsg->seq = seq;
@ -574,52 +484,6 @@ struct capwap_packet_txmng* capwap_packet_txmng_create_ctrl_message(struct capwa
return txmngpacket; return txmngpacket;
} }
/* */
struct capwap_packet_txmng* capwap_packet_txmng_create_data_message(struct capwap_header_data* data, unsigned short mtu) {
unsigned short length;
struct capwap_packet_txmng* txmngpacket;
struct capwap_fragment_packet_item* fragmentpacket;
ASSERT(data != NULL);
ASSERT(mtu > 0);
length = GET_HLEN_HEADER((struct capwap_header*)data->headerbuffer) * 4;
/* Check MTU */
if ((mtu > 0) && (mtu < (length + sizeof(struct capwap_data_message)))) {
capwap_logging_debug("The mtu is too small: %hu", mtu);
return NULL;
}
/* Create management packets */
txmngpacket = capwap_packet_txmng_create(data, mtu);
if (!txmngpacket) {
return NULL;
}
/* Get single fragment */
fragmentpacket = (struct capwap_fragment_packet_item*)txmngpacket->fragmentlist->last->item;
ASSERT((fragmentpacket->offset + sizeof(struct capwap_data_message)) < fragmentpacket->size);
/* */
txmngpacket->isctrlpacket = 0;
if (IS_FLAG_K_HEADER(txmngpacket->header)) {
txmngpacket->datamsg = (struct capwap_data_message*)&fragmentpacket->buffer[fragmentpacket->offset];
txmngpacket->datamsg->length = htons(CAPWAP_DATA_MESSAGE_KEEPALIVE_MIN_LENGTH); /* sizeof(Msg Element Length) */
fragmentpacket->offset += sizeof(struct capwap_data_message);
}
return txmngpacket;
}
/* */
void capwap_packet_txmng_add_data(struct capwap_packet_txmng* txmngpacket, const uint8_t* data, unsigned short length) {
ASSERT(txmngpacket != NULL);
ASSERT(txmngpacket->isctrlpacket == 0);
txmngpacket->write_ops.write_block((capwap_message_elements_handle)txmngpacket, data, length);
}
/* */ /* */
void capwap_packet_txmng_add_message_element(struct capwap_packet_txmng* txmngpacket, unsigned short type, void* data) { void capwap_packet_txmng_add_message_element(struct capwap_packet_txmng* txmngpacket, unsigned short type, void* data) {
struct capwap_message_elements_ops* func; struct capwap_message_elements_ops* func;
@ -807,15 +671,13 @@ static int capwap_fragment_read_u32(capwap_message_elements_handle handle, uint3
} }
/* */ /* */
struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(int isctrlpacket) { struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(void) {
struct capwap_packet_rxmng* rxmngpacket; struct capwap_packet_rxmng* rxmngpacket;
/* */ /* */
rxmngpacket = (struct capwap_packet_rxmng*)capwap_alloc(sizeof(struct capwap_packet_rxmng)); rxmngpacket = (struct capwap_packet_rxmng*)capwap_alloc(sizeof(struct capwap_packet_rxmng));
memset(rxmngpacket, 0, sizeof(struct capwap_packet_rxmng)); memset(rxmngpacket, 0, sizeof(struct capwap_packet_rxmng));
rxmngpacket->isctrlpacket = isctrlpacket;
/* Fragment bucket */ /* Fragment bucket */
rxmngpacket->fragmentlist = capwap_list_create(); rxmngpacket->fragmentlist = capwap_list_create();
@ -839,16 +701,11 @@ static void capwap_packet_rxmng_complete(struct capwap_packet_rxmng* rxmngpacket
rxmngpacket->readpos.pos = GET_HLEN_HEADER(rxmngpacket->header) * 4; rxmngpacket->readpos.pos = GET_HLEN_HEADER(rxmngpacket->header) * 4;
/* Read message type */ /* Read message type */
if (rxmngpacket->isctrlpacket) { rxmngpacket->readerpacketallowed = sizeof(struct capwap_control_message);
rxmngpacket->readerpacketallowed = sizeof(struct capwap_control_message); rxmngpacket->read_ops.read_u32((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.type);
rxmngpacket->read_ops.read_u32((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.type); rxmngpacket->read_ops.read_u8((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.seq);
rxmngpacket->read_ops.read_u8((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.seq); rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.length);
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.length); rxmngpacket->read_ops.read_u8((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.flags);
rxmngpacket->read_ops.read_u8((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.flags);
} else if (IS_FLAG_K_HEADER(rxmngpacket->header)) {
rxmngpacket->readerpacketallowed = sizeof(struct capwap_data_message);
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->datamsg.length);
}
/* Position of capwap body */ /* Position of capwap body */
memcpy(&rxmngpacket->readbodypos, &rxmngpacket->readpos, sizeof(struct read_block_from_pos)); memcpy(&rxmngpacket->readbodypos, &rxmngpacket->readpos, sizeof(struct read_block_from_pos));
@ -1016,7 +873,7 @@ struct capwap_packet_rxmng* capwap_packet_rxmng_create_from_requestfragmentpacke
} }
/* */ /* */
rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET); rxmngpacket = capwap_packet_rxmng_create_message();
/* */ /* */
fragment = requestfragmentpacket->first; fragment = requestfragmentpacket->first;

View File

@ -16,7 +16,7 @@
#define CAPWAP_NONE_PACKET 0 #define CAPWAP_NONE_PACKET 0
#define CAPWAP_PLAIN_PACKET 1 #define CAPWAP_PLAIN_PACKET 1
#define CAPWAP_DTLS_PACKET 2 #define CAPWAP_DTLS_PACKET 2
int capwap_sanity_check(int isctrlsocket, int state, void* buffer, int buffersize, int dtlsctrlenable, int dtlsdataenable); int capwap_sanity_check(int state, void* buffer, int buffersize, int dtlsenable);
/* Fragment management */ /* Fragment management */
struct capwap_fragment_packet_item { struct capwap_fragment_packet_item {
@ -50,11 +50,7 @@ struct capwap_packet_txmng {
struct capwap_header* header; struct capwap_header* header;
/* Capwap message */ /* Capwap message */
int isctrlpacket; struct capwap_control_message* ctrlmsg;
union {
struct capwap_control_message* ctrlmsg;
struct capwap_data_message* datamsg;
};
/* Write functions */ /* Write functions */
struct capwap_write_message_elements_ops write_ops; struct capwap_write_message_elements_ops write_ops;
@ -63,8 +59,6 @@ struct capwap_packet_txmng {
/* */ /* */
struct capwap_packet_txmng* capwap_packet_txmng_create_ctrl_message(struct capwap_header_data* data, unsigned long type, unsigned char seq, unsigned short mtu); struct capwap_packet_txmng* capwap_packet_txmng_create_ctrl_message(struct capwap_header_data* data, unsigned long type, unsigned char seq, unsigned short mtu);
struct capwap_packet_txmng* capwap_packet_txmng_create_data_message(struct capwap_header_data* data, unsigned short mtu);
void capwap_packet_txmng_add_data(struct capwap_packet_txmng* txmngpacket, const uint8_t* data, unsigned short length);
void capwap_packet_txmng_add_message_element(struct capwap_packet_txmng* txmngpacket, unsigned short type, void* data); void capwap_packet_txmng_add_message_element(struct capwap_packet_txmng* txmngpacket, unsigned short type, void* data);
void capwap_packet_txmng_get_fragment_packets(struct capwap_packet_txmng* txmngpacket, struct capwap_list* fragmentlist, unsigned short fragmentid); void capwap_packet_txmng_get_fragment_packets(struct capwap_packet_txmng* txmngpacket, struct capwap_list* fragmentlist, unsigned short fragmentid);
void capwap_packet_txmng_free(struct capwap_packet_txmng* txmngpacket); void capwap_packet_txmng_free(struct capwap_packet_txmng* txmngpacket);
@ -83,11 +77,7 @@ struct capwap_packet_rxmng {
struct capwap_header* header; struct capwap_header* header;
/* Capwap message */ /* Capwap message */
int isctrlpacket; struct capwap_control_message ctrlmsg;
union {
struct capwap_control_message ctrlmsg;
struct capwap_data_message datamsg;
};
/* Position of message elements or binding data */ /* Position of message elements or binding data */
struct read_block_from_pos readbodypos; struct read_block_from_pos readbodypos;
@ -106,10 +96,7 @@ struct capwap_packet_rxmng {
#define CAPWAP_REQUEST_MORE_FRAGMENT 0 #define CAPWAP_REQUEST_MORE_FRAGMENT 0
#define CAPWAP_RECEIVE_COMPLETE_PACKET 1 #define CAPWAP_RECEIVE_COMPLETE_PACKET 1
#define CAPWAP_CONTROL_PACKET 1 struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(void);
#define CAPWAP_DATA_PACKET 0
struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(int isctrlpacket);
int capwap_packet_rxmng_add_recv_packet(struct capwap_packet_rxmng* rxmngpacket, void* data, int length); int capwap_packet_rxmng_add_recv_packet(struct capwap_packet_rxmng* rxmngpacket, void* data, int length);
void capwap_packet_rxmng_free(struct capwap_packet_rxmng* rxmngpacket); void capwap_packet_rxmng_free(struct capwap_packet_rxmng* rxmngpacket);
@ -125,8 +112,4 @@ int capwap_is_request_type(unsigned long type);
#define INVALID_REQUEST_MESSAGE_TYPE 2 #define INVALID_REQUEST_MESSAGE_TYPE 2
int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket); int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket);
/* Retransmission function */
void capwap_get_packet_digest(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16]);
int capwap_recv_retrasmitted_request(struct capwap_dtls* dtls, struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16], struct capwap_list* txfragmentpacket);
#endif /* __CAPWAP_PROTOCOL_HEADER__ */ #endif /* __CAPWAP_PROTOCOL_HEADER__ */

View File

@ -1,4 +1,5 @@
#include "capwap.h" #include "capwap.h"
#include "capwap_network.h"
#include "capwap_socket.h" #include "capwap_socket.h"
#include <cyassl/options.h> #include <cyassl/options.h>
@ -30,7 +31,7 @@ static int capwap_socket_nonblocking(int sock, int nonblocking) {
} }
/* */ /* */
int capwap_socket_connect(int sock, struct sockaddr_storage* address, int timeout) { int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout) {
int result; int result;
struct pollfd fds; struct pollfd fds;
socklen_t size; socklen_t size;
@ -44,7 +45,7 @@ int capwap_socket_connect(int sock, struct sockaddr_storage* address, int timeou
} }
/* */ /* */
result = connect(sock, (struct sockaddr*)address, sizeof(struct sockaddr_storage)); result = connect(sock, &address->sa, sizeof(union sockaddr_capwap));
if (result < 0) { if (result < 0) {
if (errno == EINPROGRESS) { if (errno == EINPROGRESS) {
/* Wait to connection complete */ /* Wait to connection complete */

View File

@ -2,7 +2,7 @@
#define __CAPWAP_SOCKET_HEADER__ #define __CAPWAP_SOCKET_HEADER__
/* */ /* */
int capwap_socket_connect(int sock, struct sockaddr_storage* address, int timeout); int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout);
void capwap_socket_shutdown(int sock); void capwap_socket_shutdown(int sock);
void capwap_socket_close(int sock); void capwap_socket_close(int sock);

View File

@ -1,264 +0,0 @@
/*
**********************************************************************
** md5.c **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
/* -- include the following line if the md5.h header file is separate -- */
#include "md5.h"
/* forward declaration */
static void Transform(UINT4* buf, UINT4* in);
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G and H are basic MD5 functions: selection, majority, parity */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
void MD5Init(MD5_CTX* mdContext)
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}
void MD5Update(MD5_CTX* mdContext, unsigned char* inBuf, unsigned int inLen)
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
void MD5Final(MD5_CTX* mdContext)
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
}
/* Basic MD5 step. Transform buf based on in.
*/
static void Transform(UINT4* buf, UINT4* in)
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
FF ( a, b, c, d, in[ 0], S11, 0xd76aa478); /* 1 */
FF ( d, a, b, c, in[ 1], S12, 0xe8c7b756); /* 2 */
FF ( c, d, a, b, in[ 2], S13, 0x242070db); /* 3 */
FF ( b, c, d, a, in[ 3], S14, 0xc1bdceee); /* 4 */
FF ( a, b, c, d, in[ 4], S11, 0xf57c0faf); /* 5 */
FF ( d, a, b, c, in[ 5], S12, 0x4787c62a); /* 6 */
FF ( c, d, a, b, in[ 6], S13, 0xa8304613); /* 7 */
FF ( b, c, d, a, in[ 7], S14, 0xfd469501); /* 8 */
FF ( a, b, c, d, in[ 8], S11, 0x698098d8); /* 9 */
FF ( d, a, b, c, in[ 9], S12, 0x8b44f7af); /* 10 */
FF ( c, d, a, b, in[10], S13, 0xffff5bb1); /* 11 */
FF ( b, c, d, a, in[11], S14, 0x895cd7be); /* 12 */
FF ( a, b, c, d, in[12], S11, 0x6b901122); /* 13 */
FF ( d, a, b, c, in[13], S12, 0xfd987193); /* 14 */
FF ( c, d, a, b, in[14], S13, 0xa679438e); /* 15 */
FF ( b, c, d, a, in[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
GG ( a, b, c, d, in[ 1], S21, 0xf61e2562); /* 17 */
GG ( d, a, b, c, in[ 6], S22, 0xc040b340); /* 18 */
GG ( c, d, a, b, in[11], S23, 0x265e5a51); /* 19 */
GG ( b, c, d, a, in[ 0], S24, 0xe9b6c7aa); /* 20 */
GG ( a, b, c, d, in[ 5], S21, 0xd62f105d); /* 21 */
GG ( d, a, b, c, in[10], S22, 0x02441453); /* 22 */
GG ( c, d, a, b, in[15], S23, 0xd8a1e681); /* 23 */
GG ( b, c, d, a, in[ 4], S24, 0xe7d3fbc8); /* 24 */
GG ( a, b, c, d, in[ 9], S21, 0x21e1cde6); /* 25 */
GG ( d, a, b, c, in[14], S22, 0xc33707d6); /* 26 */
GG ( c, d, a, b, in[ 3], S23, 0xf4d50d87); /* 27 */
GG ( b, c, d, a, in[ 8], S24, 0x455a14ed); /* 28 */
GG ( a, b, c, d, in[13], S21, 0xa9e3e905); /* 29 */
GG ( d, a, b, c, in[ 2], S22, 0xfcefa3f8); /* 30 */
GG ( c, d, a, b, in[ 7], S23, 0x676f02d9); /* 31 */
GG ( b, c, d, a, in[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
HH ( a, b, c, d, in[ 5], S31, 0xfffa3942); /* 33 */
HH ( d, a, b, c, in[ 8], S32, 0x8771f681); /* 34 */
HH ( c, d, a, b, in[11], S33, 0x6d9d6122); /* 35 */
HH ( b, c, d, a, in[14], S34, 0xfde5380c); /* 36 */
HH ( a, b, c, d, in[ 1], S31, 0xa4beea44); /* 37 */
HH ( d, a, b, c, in[ 4], S32, 0x4bdecfa9); /* 38 */
HH ( c, d, a, b, in[ 7], S33, 0xf6bb4b60); /* 39 */
HH ( b, c, d, a, in[10], S34, 0xbebfbc70); /* 40 */
HH ( a, b, c, d, in[13], S31, 0x289b7ec6); /* 41 */
HH ( d, a, b, c, in[ 0], S32, 0xeaa127fa); /* 42 */
HH ( c, d, a, b, in[ 3], S33, 0xd4ef3085); /* 43 */
HH ( b, c, d, a, in[ 6], S34, 0x04881d05); /* 44 */
HH ( a, b, c, d, in[ 9], S31, 0xd9d4d039); /* 45 */
HH ( d, a, b, c, in[12], S32, 0xe6db99e5); /* 46 */
HH ( c, d, a, b, in[15], S33, 0x1fa27cf8); /* 47 */
HH ( b, c, d, a, in[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
II ( a, b, c, d, in[ 0], S41, 0xf4292244); /* 49 */
II ( d, a, b, c, in[ 7], S42, 0x432aff97); /* 50 */
II ( c, d, a, b, in[14], S43, 0xab9423a7); /* 51 */
II ( b, c, d, a, in[ 5], S44, 0xfc93a039); /* 52 */
II ( a, b, c, d, in[12], S41, 0x655b59c3); /* 53 */
II ( d, a, b, c, in[ 3], S42, 0x8f0ccc92); /* 54 */
II ( c, d, a, b, in[10], S43, 0xffeff47d); /* 55 */
II ( b, c, d, a, in[ 1], S44, 0x85845dd1); /* 56 */
II ( a, b, c, d, in[ 8], S41, 0x6fa87e4f); /* 57 */
II ( d, a, b, c, in[15], S42, 0xfe2ce6e0); /* 58 */
II ( c, d, a, b, in[ 6], S43, 0xa3014314); /* 59 */
II ( b, c, d, a, in[13], S44, 0x4e0811a1); /* 60 */
II ( a, b, c, d, in[ 4], S41, 0xf7537e82); /* 61 */
II ( d, a, b, c, in[11], S42, 0xbd3af235); /* 62 */
II ( c, d, a, b, in[ 2], S43, 0x2ad7d2bb); /* 63 */
II ( b, c, d, a, in[ 9], S44, 0xeb86d391); /* 64 */
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}

View File

@ -1,53 +0,0 @@
/*
**********************************************************************
** md5.h -- Header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
**********************************************************************
*/
/*
**********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
**********************************************************************
*/
/* typedef a 32 bit type */
typedef unsigned long int UINT4;
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5Init(MD5_CTX* mdContext);
void MD5Update(MD5_CTX* mdContext, unsigned char* inBuf, unsigned int inLen);
void MD5Final(MD5_CTX* mdContext);

View File

@ -3,6 +3,7 @@
#include "capwap_element.h" #include "capwap_element.h"
#include "wifi_drivers.h" #include "wifi_drivers.h"
#include "wtp_radio.h" #include "wtp_radio.h"
#include "wtp_kmod.h"
/* Declare enable wifi driver */ /* Declare enable wifi driver */
#ifdef ENABLE_WIFI_DRIVERS_NL80211 #ifdef ENABLE_WIFI_DRIVERS_NL80211
@ -314,7 +315,7 @@ static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const u
capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress);
/* Forwards the station deauthentication also to AC */ /* Forwards the station deauthentication also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else { } else {
capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress);
} }
@ -419,7 +420,7 @@ static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan,
if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) {
/* If enable Split Mac send the probe request message to AC */ /* If enable Split Mac send the probe request message to AC */
if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
} }
} else { } else {
capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); capwap_logging_warning("Unable to send IEEE802.11 Probe Response");
@ -583,10 +584,10 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode); capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode);
/* Notify authentication request message also to AC */ /* Notify authentication request message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Forwards the authentication response message also to AC */ /* Forwards the authentication response message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else if (station) { } else if (station) {
capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress); capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress);
wifi_station_delete(station); wifi_station_delete(station);
@ -596,7 +597,7 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
wifi_station_delete(station); wifi_station_delete(station);
} }
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
} }
} }
@ -682,10 +683,10 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan*
capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode);
/* Notify association request message also to AC */ /* Notify association request message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Forwards the association response message also to AC */ /* Forwards the association response message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else { } else {
capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext);
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
@ -695,7 +696,7 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan*
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
} }
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Station information */ /* Station information */
station->capability = __le16_to_cpu(frame->associationresponse.capability); station->capability = __le16_to_cpu(frame->associationresponse.capability);
@ -729,7 +730,7 @@ static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan
/* TODO */ /* TODO */
/* Notify disassociation message also to AC */ /* Notify disassociation message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
} }
/* */ /* */
@ -750,7 +751,7 @@ static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wl
} }
/* Notify deauthentication message also to AC */ /* Notify deauthentication message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
} }
/* */ /* */
@ -1479,8 +1480,8 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
wlan->authmode = params->authmode; wlan->authmode = params->authmode;
wlan->macmode = params->macmode; wlan->macmode = params->macmode;
wlan->tunnelmode = params->tunnelmode; wlan->tunnelmode = params->tunnelmode;
wlan->send_frame = params->send_frame; wlan->radioid = params->radioid;
wlan->send_frame_to_ac_cbparam = params->send_frame_to_ac_cbparam; wlan->wlanid = params->wlanid;
/* Start AP */ /* Start AP */
result = wlan->device->instance->ops->wlan_startap(wlan); result = wlan->device->instance->ops->wlan_startap(wlan);
@ -1655,16 +1656,23 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
} }
/* */ /* */
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate) { int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate) {
int result;
ASSERT(wlan != NULL); ASSERT(wlan != NULL);
ASSERT(wlan->handle != NULL); ASSERT(wlan->handle != NULL);
if (!data || (length <= 0) || !wlan->send_frame) { if (!data || (length <= 0)) {
return -1; return -1;
} }
/* */ /* Send packet to AC */
return wlan->send_frame(wlan->send_frame_to_ac_cbparam, data, length, nativeframe, rssi, snr, rate, wlan->address, MACADDRESS_EUI48_LENGTH); result = wtp_kmod_send_data(wlan->radioid, data, length, rssi, snr, rate);
if (result) {
capwap_logging_warning("Unable to sent packet to AC: %d error code", result);
}
return result;
} }
/* */ /* */
@ -1704,23 +1712,17 @@ int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* pa
} }
/* */ /* */
int wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) { void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) {
struct wifi_station* station; struct wifi_station* station;
ASSERT(device != NULL); ASSERT(device != NULL);
ASSERT(address != NULL); ASSERT(address != NULL);
/* Get station */ /* */
station = wifi_station_get(NULL, address); station = wifi_station_get(NULL, address);
if (!station || !station->wlan) { if (station && station->wlan) {
return -1; wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
} }
/* Station deauthorized */
capwap_logging_info("Deauthorize station: %s", station->addrtext);
wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
return 1;
} }
/* */ /* */

View File

@ -87,11 +87,11 @@ struct device_setconfiguration_params {
}; };
/* */ /* */
typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype); typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate);
struct wlan_startap_params { struct wlan_startap_params {
send_frame_to_ac send_frame; uint8_t radioid;
void* send_frame_to_ac_cbparam; uint8_t wlanid;
const char* ssid; const char* ssid;
uint8_t ssid_hidden; uint8_t ssid_hidden;
@ -289,8 +289,8 @@ struct wifi_wlan {
uint8_t address[MACADDRESS_EUI48_LENGTH]; uint8_t address[MACADDRESS_EUI48_LENGTH];
/* */ /* */
send_frame_to_ac send_frame; uint8_t radioid;
void* send_frame_to_ac_cbparam; uint8_t wlanid;
/* WLAN information */ /* WLAN information */
char ssid[IEEE80211_SSID_MAX_LENGTH + 1]; char ssid[IEEE80211_SSID_MAX_LENGTH + 1];
@ -409,7 +409,7 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
void wifi_wlan_stopap(struct wifi_wlan* wlan); void wifi_wlan_stopap(struct wifi_wlan* wlan);
int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid); int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid);
uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability); uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability);
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate); int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate);
void wifi_wlan_destroy(struct wifi_wlan* wlan); void wifi_wlan_destroy(struct wifi_wlan* wlan);
/* WLAN packet management */ /* WLAN packet management */
@ -419,7 +419,7 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
/* Station management */ /* Station management */
int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params); int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params);
int wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address); void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address);
/* Util functions */ /* Util functions */
uint32_t wifi_iface_index(const char* ifname); uint32_t wifi_iface_index(const char* ifname);

View File

@ -759,6 +759,7 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
return -1; return -1;
} }
/* */
nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL);
nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan); nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan);
@ -798,16 +799,13 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
/* */ /* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* Join interface to kernel module */ /* Join interface in kernel module */
if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) { uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023);
uint32_t mode = ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) ? WTP_KMOD_MODE_TUNNEL_KERNELMODE : WTP_KMOD_MODE_TUNNEL_USERMODE);
uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023);
if (!wtp_kmod_join_mac80211_device(wlan, mode, flags)) { if (!wtp_kmod_join_mac80211_device(wlan, flags)) {
capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex); capwap_logging_info("Joined the interface %d in kernel mode ", wlan->virtindex);
}
} else { } else {
capwap_logging_warning("Tunneling is not supported for interface %d", wlan->virtindex); capwap_logging_error("Unable to join the interface %d in kernel mode ", wlan->virtindex);
return -1; return -1;
} }
} }
@ -833,9 +831,7 @@ static void nl80211_wlan_stopap(struct wifi_wlan* wlan) {
/* */ /* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* Leave interface from kernel module */ /* Leave interface from kernel module */
if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) { wtp_kmod_leave_mac80211_device(wlan);
wtp_kmod_leave_mac80211_device(wlan);
}
} }
/* */ /* */
@ -1068,6 +1064,12 @@ int nl80211_station_deauthorize(struct wifi_wlan* wlan, const uint8_t* address)
} }
} }
/* */
if (!result) {
char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER];
capwap_logging_info("Deauthorize station: %s", capwap_printf_macaddress(addrtext, address, MACADDRESS_EUI48_LENGTH));
}
/* */ /* */
nlmsg_free(msg); nlmsg_free(msg);
return result; return result;

View File

@ -2,4 +2,7 @@ obj-m += smartcapwap.o
smartcapwap-y := \ smartcapwap-y := \
main.o \ main.o \
netlinkapp.o netlinkapp.o \
socket.o \
capwap.o \
capwap_private.o

621
src/wtp/kmod/capwap.c Normal file
View File

@ -0,0 +1,621 @@
#include "config.h"
#include <linux/module.h>
#include <linux/ieee80211.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
#define TIMEOUT_PACKET 10
/* */
union capwap_addr sc_localaddr;
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
TRACEKMOD("### sc_capwap_fragment_free\n");
/* */
list_del(&fragment->lru_list);
fragment->flags = 0;
/* Free socket buffer */
while (fragment->fragments) {
struct sk_buff* next = fragment->fragments->next;
kfree_skb(fragment->fragments);
fragment->fragments = next;
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
unsigned long flags;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_defrag_evictor\n");
/* */
if (now.tv64 == 0) {
TRACEKMOD("*** Get time\n");
now = ktime_get();
}
/* Remove last old fragment */
if (!list_empty(&session->fragments.lru_list)) {
spin_lock_irqsave(&session->fragments.lock, flags);
fragment = list_first_entry(&session->fragments.lru_list, struct sc_capwap_fragment, lru_list);
if (fragment) {
delta = ktime_sub(now, fragment->tstamp);
if ((delta.tv64 < 0) || (delta.tv64 > NSEC_PER_SEC)) {
TRACEKMOD("*** Expired fragment %hu\n", fragment->fragmentid);
/* Reset fragment */
sc_capwap_fragment_free(fragment);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
}
}
/* */
static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) {
int len;
int offset;
struct sk_buff* skb;
struct sk_buff* skbfrag;
struct sc_capwap_header* header;
/* */
skbfrag = fragment->fragments;
len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
/* Create new packet */
skb = alloc_skb(len + fragment->totallength, GFP_KERNEL);
if (!skb) {
return NULL;
}
/* The first capwap header is header of reassembled packet without fragment field */
header = (struct sc_capwap_header*)skb_put(skb, len);
memcpy(header, skb->data, len);
SET_FLAG_F_HEADER(header, 0);
SET_FLAG_L_HEADER(header, 0);
header->frag_id = (__be16)0;
header->frag_off = (__be16)0;
/* Copy body */
while (skbfrag) {
offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
len = skb->len - offset;
/* */
memcpy(skb_put(skb, len), skb->data + offset, len);
skbfrag = skbfrag->next;
}
return skb;
}
/* */
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
unsigned long flags;
uint16_t headersize;
uint16_t frag_id;
struct sk_buff* prev;
struct sk_buff* next;
struct sc_capwap_fragment* fragment;
struct sc_skb_capwap_cb* cb;
struct sk_buff* skb_defrag = NULL;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_defrag\n");
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if (skb->len < headersize) {
goto error;
}
/* */
frag_id = be16_to_cpu(header->frag_id);
/* */
cb = CAPWAP_SKB_CB(skb);
cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT;
cb->frag_offset = be16_to_cpu(header->frag_off);
cb->frag_length = skb->len - headersize;
/* */
spin_lock_irqsave(&session->fragments.lock, flags);
/* Get fragment */
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) {
goto error2; /* Queue fragment busy*/
}
/* Init fragment */
if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) {
fragment->flags = CAPWAP_FRAGMENT_ENABLE;
fragment->fragmentid = frag_id;
fragment->fragments = NULL;
fragment->lastfragment = NULL;
fragment->recvlength = 0;
fragment->totallength = 0;
list_add_tail(&fragment->lru_list, &session->fragments.lru_list);
}
/* Search fragment position */
prev = fragment->lastfragment;
if (!prev) {
next = NULL;
} else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) {
if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) < cb->frag_offset) {
next = NULL;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
} else {
prev = NULL;
for (next = fragment->fragments; next != NULL; next = next->next) {
struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next);
if (next_cb->frag_offset < cb->frag_offset) {
if ((next_cb->frag_offset + next_cb->frag_length) < cb->frag_offset) {
break;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
}
prev = next;
}
}
/* Insert fragment */
skb->prev = NULL;
skb->next = next;
if (!next) {
fragment->lastfragment = skb;
}
if (prev) {
prev->next = skb;
} else {
fragment->fragments = skb;
}
/* Update size */
fragment->recvlength += cb->frag_length;
if (IS_FLAG_L_HEADER(header)) {
fragment->totallength = cb->frag_offset + cb->frag_length;
fragment->flags |= CAPWAP_FRAGMENT_LAST;
}
/* Check if receive all fragment */
if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) {
skb_defrag = sc_capwap_reasm(fragment);
/* Free fragment complete */
sc_capwap_fragment_free(fragment);
} else {
/* Update timeout */
fragment->tstamp = skb->tstamp;
if (fragment->tstamp.tv64 == 0) {
fragment->tstamp = ktime_get();
}
/* Set LRU timeout */
if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) {
list_move_tail(&fragment->lru_list, &session->fragments.lru_list);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
return skb_defrag;
error2:
spin_unlock_irqrestore(&session->fragments.lock, flags);
error:
kfree_skb(skb);
return NULL;
}
/* */
int sc_capwap_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_capwap_bind\n");
/* */
ret = sc_socket_bind(sockaddr);
if (ret) {
return ret;
}
memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr));
return 0;
}
/* */
void sc_capwap_initsession(struct sc_capwap_session* session) {
TRACEKMOD("### sc_capwap_initsession\n");
INIT_LIST_HEAD(&session->list);
spin_lock_init(&session->fragmentid_lock);
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
}
/* */
void sc_capwap_freesession(struct sc_capwap_session* session) {
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
}
/* */
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
uint16_t fragmentid;
unsigned long flags;
TRACEKMOD("### sc_capwap_newfragmentid\n");
spin_lock_irqsave(&session->fragmentid_lock, flags);
fragmentid = session->fragmentid++;
spin_unlock_irqrestore(&session->fragmentid_lock, flags);
return fragmentid;
}
/* */
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) {
int length;
struct sc_capwap_header* header;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* msgelement;
TRACEKMOD("### sc_capwap_createkeepalive\n");
/* */
if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) {
return -ENOMEM;
}
/* Preamble CAPWAP header */
header = (struct sc_capwap_header*)buffer;
length = sizeof(struct sc_capwap_header);
buffer += sizeof(struct sc_capwap_header);
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4);
SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211);
SET_FLAG_K_HEADER(header, 1);
/* CAPWAP Data header */
dataheader = (struct sc_capwap_data_message*)buffer;
length += sizeof(struct sc_capwap_data_message);
buffer += sizeof(struct sc_capwap_data_message);
dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element));
/* CAPWAP Keep-Alive Message Element */
msgelement = (struct sc_capwap_message_element*)buffer;
length += sizeof(struct sc_capwap_message_element);
buffer += sizeof(struct sc_capwap_message_element);
msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID);
msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element));
/* Session ID */
memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element));
length += sizeof(struct sc_capwap_sessionid_element);
return length;
}
/* */
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) {
int length;
uint16_t headersize;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* message;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_parsingpacket\n");
/* Linearize socket buffer */
if (skb_linearize(skb)) {
TRACEKMOD("*** Unable to linearize packet\n");
return -EINVAL;
}
/* Check header */
if (skb->len < sizeof(struct sc_capwap_header)) {
TRACEKMOD("*** Invalid capwap header length\n");
return -EINVAL;
} else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) {
TRACEKMOD("*** Invalid capwap header version\n");
return -EINVAL;
} else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) {
TRACEKMOD("*** Packet is encrypted\n");
return -EINVAL; /* Accept only plain packet */
}
/* Cleaning old fragments */
if (session) {
sc_capwap_defrag_evictor(session, skb->tstamp);
}
/* */
if (IS_FLAG_K_HEADER(header)) {
/* Keep alive can not fragment */
if (IS_FLAG_F_HEADER(header)) {
TRACEKMOD("*** Keep alive can not fragment\n");
return -EINVAL;
}
/* */
length = skb->len;
headersize = GET_HLEN_HEADER(header) * 4;
if (length < (headersize + sizeof(struct sc_capwap_data_message))) {
TRACEKMOD("*** Invalid capwap data header length\n");
return -EINVAL;
}
/* Data message */
length -= headersize;
dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize);
headersize = ntohs(dataheader->length);
if (length < headersize) {
TRACEKMOD("*** Capwap data header length mismatch\n");
return -EINVAL;
}
/* Message elements */
headersize -= sizeof(struct sc_capwap_data_message);
message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message));
while (headersize > 0) {
uint16_t msglength = ntohs(message->length);
if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) {
TRACEKMOD("*** Invalid capwap message element length\n");
return -EINVAL;
}
/* */
if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) {
struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element));
if (!session) {
session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid);
if (!session) {
TRACEKMOD("*** Receive unknown keep alive without valid session\n");
return -EINVAL;
}
} else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
TRACEKMOD("*** Session id mismatch\n");
return -EINVAL;
}
/* Session found */
sc_netlink_notify_recv_keepalive(sockaddr, sessionid);
/* Parsing complete */
kfree_skb(skb);
return 0;
}
/* Next message element */
msglength += sizeof(struct sc_capwap_message_element);
message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength);
headersize -= msglength;
}
} else if (session) {
if (IS_FLAG_F_HEADER(header)) {
skb = sc_capwap_defrag(session, skb);
if (!skb) {
return 0;
}
/* Get new header info */
header = (struct sc_capwap_header*)skb->data;
}
/* Parsing data/management packet */
if (!IS_FLAG_T_HEADER(header)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4);
if (ieee80211_is_data_present(hdr->frame_control)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) {
sc_capwap_parsingmgmtpacket(session, skb);
}
}
/* Parsing complete */
kfree_skb(skb);
return 0;
}
return -EINVAL;
}
/* */
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) {
int size;
int length;
int reserve;
int headroom;
int requestfragment;
__be16 fragmentid = 0;
int fragmentoffset = 0;
struct sc_capwap_header* header;
struct sk_buff* clone = NULL;
int packetlength = skb->len;
TRACEKMOD("### sc_capwap_forwarddata\n");
/* Check headroom */
headroom = skb_headroom(skb);
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
printk("*** Expand socket buffer\n");
clone = skb_copy_expand(skb, max_t(int, headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
if (!clone) {
printk("*** Unable to expand socket buffer\n");
return -ENOMEM;
}
skb = clone;
}
/* Check MTU */
requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0);
if (requestfragment) {
fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session));
}
/* */
header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength);
while (packetlength > 0) {
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_WBID_HEADER(header, binding);
SET_RID_HEADER(header, radioid);
SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1));
if (!fragmentoffset) {
uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header);
if (radioaddr) {
SET_FLAG_M_HEADER(header, 1);
memcpy(headeroption, radioaddr, radioaddrlength);
headeroption += radioaddrlength;
}
if (winfo) {
SET_FLAG_W_HEADER(header, 1);
memcpy(headeroption, winfo, winfolength);
headeroption += winfolength;
}
size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
SET_HLEN_HEADER(header, size / 4);
} else {
size = sizeof(struct sc_capwap_header);
SET_HLEN_HEADER(header, size / 4);
}
/* Calculate body size */
length = session->mtu - size;
if (packetlength <= length) {
length = packetlength;
} else if (requestfragment) {
length -= length % 8; /* Capwap fragment size is module 8 */
} else {
break;
}
/* Fragment options */
if (requestfragment) {
SET_FLAG_F_HEADER(header, 1);
if (packetlength == length) {
SET_FLAG_L_HEADER(header, 1);
}
header->frag_id = fragmentid;
header->frag_off = cpu_to_be16(fragmentoffset);
}
/* Send packet */
if (sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr) < 0) {
break;
}
/* */
header = (struct sc_capwap_header*)((uint8_t*)header + (size + length));
fragmentoffset += length;
packetlength -= length;
}
if (clone) {
kfree_skb(clone);
}
return (!packetlength ? 0 : -EIO);
}
/* */
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) {
int i;
char* pos = string;
for (i = 0; i < 16; i++) {
snprintf(pos, 3, "%02x", sessionid->id[i]);
pos += 2;
}
*pos = 0;
}
/* */
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) {
struct sc_capwap_radio_addr* radioaddr;
struct sc_capwap_macaddress_eui48* addr;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
radioaddr = (struct sc_capwap_radio_addr*)buffer;
radioaddr->length = MACADDRESS_EUI48_LENGTH;
addr = (struct sc_capwap_macaddress_eui48*)(buffer + sizeof(struct sc_capwap_radio_addr));
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
return radioaddr;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) {
struct sc_capwap_wireless_information* winfo;
struct sc_capwap_ieee80211_frame_info* frameinfo;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
winfo = (struct sc_capwap_wireless_information*)buffer;
winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info);
frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information));
frameinfo->rssi = rssi;
frameinfo->snr = snr;
frameinfo->rate = cpu_to_be16(rate);
return winfo;
}

128
src/wtp/kmod/capwap.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
#define MAX_MTU 9000
#define DEFAULT_MTU 1450
#define MIN_MTU 500
#define IEEE80211_MTU 7981
/* */
#define CAPWAP_FRAGMENT_QUEUE 16
/* */
#define CAPWAP_FRAGMENT_ENABLE 0x0001
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
#define CAPWAP_FRAGMENT_LAST 0x0004
/* */
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0004
#define SKB_CAPWAP_FLAG_PEERADDRESS 0x0010
#define SKB_CAPWAP_FLAG_RADIOID 0x0020
#define SKB_CAPWAP_FLAG_BINDING 0x0040
#define SKB_CAPWAP_FLAG_RADIOADDRESS 0x0080
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0100
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
struct sc_skb_capwap_cb {
uint16_t flags;
struct capwap_addr_little peeraddr;
/* Capwap information */
uint8_t radioid;
uint8_t binding;
/* Radio Address */
uint8_t radioaddr_addr[MACADDRESS_EUI48_LENGTH];
/* Wireless Information */
uint8_t winfo_rssi;
uint8_t winfo_snr;
uint16_t winfo_rate;
/* Fragment */
uint16_t frag_offset;
uint16_t frag_length;
};
#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb))
/* */
struct sc_capwap_fragment {
struct list_head lru_list;
uint8_t flags;
ktime_t tstamp;
uint16_t fragmentid;
struct sk_buff* fragments;
struct sk_buff* lastfragment;
int recvlength;
int totallength;
};
/* */
struct sc_capwap_fragment_queue {
spinlock_t lock;
struct list_head lru_list;
struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE];
};
/* */
struct sc_capwap_session {
struct list_head list;
struct sc_capwap_session* __rcu next;
uint16_t mtu;
union capwap_addr peeraddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t fragmentid;
spinlock_t fragmentid_lock;
struct sc_capwap_fragment_queue fragments;
};
/* */
extern union capwap_addr sc_localaddr;
/* Dipendent implementation function */
void sc_capwap_recvpacket(struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb);
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(union capwap_addr* sockaddr);
void sc_capwap_initsession(struct sc_capwap_session* session);
void sc_capwap_freesession(struct sc_capwap_session* session);
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
struct sc_capwap_packet* sc_capwap_poppacketqueue(struct sc_capwap_session* session);
void sc_capwap_pushpacketqueue(struct sc_capwap_session* session, struct sc_capwap_packet* packet);
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength);
/* Private funciotn */
#include "capwap_private.h"
#endif /* __KMOD_CAPWAP_HEADER__ */

View File

@ -0,0 +1,164 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kthread.h>
#include <net/ipv6.h>
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
static struct sc_capwap_session sc_acsession;
/* */
int sc_capwap_init(uint32_t threads) {
TRACEKMOD("### sc_capwap_init\n");
/* Init session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
/* Init sockect */
return sc_socket_init();
}
/* */
void sc_capwap_close(void) {
TRACEKMOD("### sc_capwap_close\n");
/* */
sc_socket_close();
sc_capwap_freesession(&sc_acsession);
}
/* */
int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) {
TRACEKMOD("### sc_capwap_connect\n");
if ((sc_localaddr.ss.ss_family != AF_INET) && (sc_localaddr.ss.ss_family != AF_INET6)) {
return -ENONET;
}
/* AC address */
if ((sockaddr->ss.ss_family == AF_INET6) && ipv6_addr_v4mapped(&sockaddr->sin6.sin6_addr)) {
return -EINVAL;
} else if ((sc_localaddr.ss.ss_family == AF_INET) && (sockaddr->ss.ss_family == AF_INET6)) {
return -EINVAL;
}
/* */
memcpy(&sc_acsession.peeraddr, sockaddr, sizeof(union capwap_addr));
memcpy(&sc_acsession.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
sc_acsession.mtu = mtu;
return sc_capwap_sendkeepalive();
}
/* */
void sc_capwap_resetsession(void) {
sc_capwap_freesession(&sc_acsession);
/* Reinit session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
}
/* */
int sc_capwap_sendkeepalive(void) {
int ret;
int length;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
TRACEKMOD("### sc_capwap_sendkeepalive\n");
/* Build keepalive */
length = sc_capwap_createkeepalive(&sc_acsession.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr);
if (ret > 0) {
ret = 0;
}
return ret;
}
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) {
TRACEKMOD("### sc_capwap_getsession\n");
if (!sockaddr) {
return &sc_acsession;
} else if (sc_acsession.peeraddr.ss.ss_family == sockaddr->ss.ss_family) {
if (sc_acsession.peeraddr.ss.ss_family == AF_INET) {
if ((sc_acsession.peeraddr.sin.sin_port == sockaddr->sin.sin_port) && (sc_acsession.peeraddr.sin.sin_addr.s_addr == sockaddr->sin.sin_addr.s_addr)) {
return &sc_acsession;
}
} else if (sc_acsession.peeraddr.ss.ss_family == AF_INET6) {
if ((sc_acsession.peeraddr.sin6.sin6_port == sockaddr->sin6.sin6_port) && !ipv6_addr_cmp(&sc_acsession.peeraddr.sin6.sin6_addr, &sockaddr->sin6.sin6_addr)) {
return &sc_acsession;
}
}
}
return NULL;
}
/* */
void sc_capwap_recvpacket(struct sk_buff* skb) {
union capwap_addr peeraddr;
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_recvpacket\n");
/* Get peer address */
if (sc_socket_getpeeraddr(skb, &peeraddr)) {
goto drop;
}
/* Get session */
session = sc_capwap_getsession(&peeraddr);
if (!session) {
TRACEKMOD("*** Session not found\n");
goto drop;
}
/* Remove UDP header */
if (!skb_pull(skb, sizeof(struct udphdr))) {
TRACEKMOD("*** Invalid packet\n");
goto drop;
}
/* Parsing packet */
if (sc_capwap_parsingpacket(session, &peeraddr, skb)) {
TRACEKMOD("*** Parsing error\n");
goto drop;
}
return;
drop:
kfree_skb(skb);
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
return NULL;
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingdatapacket\n");
}
/* */
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingmgmtpacket\n");
/* Send packet with capwap header into userspace */
sc_netlink_notify_recv_data(skb->data, skb->len);
}

View File

@ -0,0 +1,27 @@
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
#define __KMOD_CAPWAP_PRIVATE_HEADER__
/* */
struct sc_capwap_workthread {
struct task_struct* thread;
struct sk_buff_head queue;
wait_queue_head_t waitevent;
};
/* */
int sc_capwap_init(uint32_t threads);
void sc_capwap_close(void);
/* */
int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu);
void sc_capwap_resetsession(void);
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr);
/* */
int sc_capwap_sendkeepalive(void);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

172
src/wtp/kmod/capwap_rfc.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef __KMOD_CAPWAP_RFC_HEADER__
#define __KMOD_CAPWAP_RFC_HEADER__
#include <linux/types.h>
#include <asm/byteorder.h>
/* */
#define CAPWAP_RADIOID_MAX_COUNT 31
#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT))
#define CAPWAP_WLANID_MAX_COUNT 16
#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT))
/* */
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_ELEMENT_SESSIONID 35
/* */
#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \
sizeof(struct sc_capwap_header) + \
sizeof(struct sc_capwap_data_message) + \
sizeof(struct sc_capwap_message_element) + \
sizeof(struct sc_capwap_sessionid_element))
/* Preamble */
struct sc_capwap_preamble {
#if defined(__BIG_ENDIAN_BITFIELD)
uint8_t version: 4,
type: 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t type: 4,
version: 4;
#endif
} __packed;
/* DTLS header */
struct sc_capwap_dtls_header {
struct sc_capwap_preamble preamble;
uint8_t reserved[3];
} __packed;
/* Plain header */
struct sc_capwap_header {
struct sc_capwap_preamble preamble;
#if defined(__BIG_ENDIAN_BITFIELD)
uint16_t hlen: 5,
rid: 5,
wbid: 5,
flag_t: 1;
uint8_t flag_f: 1,
flag_l: 1,
flag_w: 1,
flag_m: 1,
flag_k: 1,
flag_res: 3;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint16_t _rid_hi: 3,
hlen: 5,
flag_t: 1,
wbid: 5,
_rid_lo: 2;
uint8_t flag_res: 3,
flag_k: 1,
flag_m: 1,
flag_w: 1,
flag_l: 1,
flag_f: 1;
#endif
__be16 frag_id;
__be16 frag_off;
} __packed;
/* Mac Address */
#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8
#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12
#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12
struct sc_capwap_radio_addr {
uint8_t length;
} __packed;
/* Wireless Information */
#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8
#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8
#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8
struct sc_capwap_wireless_information {
uint8_t length;
} __packed;
/* IEEE802.11 Wireless Information */
struct sc_capwap_ieee80211_frame_info {
uint8_t rssi;
uint8_t snr;
__be16 rate;
} __packed;
/* */
#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED)
/* Data channel message */
struct sc_capwap_data_message {
__be16 length;
} __packed;
/* Message element */
struct sc_capwap_message_element {
__be16 type;
__be16 length;
} __packed;
/* Session id message element */
struct sc_capwap_sessionid_element {
uint8_t id[16];
} __packed;
/* */
#define MACADDRESS_EUI48_LENGTH 6
struct sc_capwap_macaddress_eui48 {
uint8_t addr[MACADDRESS_EUI48_LENGTH];
} __packed;
/* */
#define MACADDRESS_EUI64_LENGTH 8
struct sc_capwap_macaddress_eui64 {
uint8_t addr[MACADDRESS_EUI64_LENGTH];
} __packed;
/* Capwap preamble */
#define CAPWAP_PROTOCOL_VERSION 0
#define CAPWAP_PREAMBLE_HEADER 0
#define CAPWAP_PREAMBLE_DTLS_HEADER 1
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element))
/* */
#define GET_VERSION_HEADER(x) ((x)->preamble.version)
#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y))
#define GET_TYPE_HEADER(x) ((x)->preamble.type)
#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y))
#define GET_HLEN_HEADER(x) ((x)->hlen)
#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y))
#if defined(__BIG_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((x)->rid))
#define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y))
#elif defined(__LITTLE_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo)))
#define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); })
#endif
#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid))
#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y))
#define IS_FLAG_T_HEADER(x) ((x)->flag_t)
#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0))
#define IS_FLAG_F_HEADER(x) ((x)->flag_f)
#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0))
#define IS_FLAG_L_HEADER(x) ((x)->flag_l)
#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0))
#define IS_FLAG_W_HEADER(x) ((x)->flag_w)
#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0))
#define IS_FLAG_M_HEADER(x) ((x)->flag_m)
#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0))
#define IS_FLAG_K_HEADER(x) ((x)->flag_k)
#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0))
#endif /* __KMOD_CAPWAP_RFC_HEADER__ */

13
src/wtp/kmod/config.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __KMOD_CONFIG_HEADER__
#define __KMOD_CONFIG_HEADER__
#define DEBUGKMOD 1
#ifdef DEBUGKMOD
#define TRACEKMOD(s, args...) printk(s, ##args)
#else
#define TRACEKMOD(s, args...)
#endif
#endif /* __KMOD_CONFIG_HEADER__ */

View File

@ -1,23 +1,31 @@
#include "config.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include "netlinkapp.h" #include "netlinkapp.h"
/* */ /* */
static int __init smartcapwap_init(void) { static int __init smartcapwap_wtp_init(void) {
int result = 0; int ret;
/* */ TRACEKMOD("### smartcapwap_wtp_init\n");
result = nlsmartcapwap_init();
return result; /* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
} }
module_init(smartcapwap_init); module_init(smartcapwap_wtp_init);
/* */ /* */
static void __exit smartcapwap_exit(void) { static void __exit smartcapwap_wtp_exit(void) {
nlsmartcapwap_exit(); TRACEKMOD("### smartcapwap_wtp_exit\n");
sc_netlink_exit();
} }
module_exit(smartcapwap_exit); module_exit(smartcapwap_wtp_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>"); MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");

View File

@ -1,5 +1,7 @@
#include "config.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/netdevice.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
@ -8,154 +10,200 @@
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include "nlsmartcapwap.h" #include "nlsmartcapwap.h"
#include "netlinkapp.h" #include "netlinkapp.h"
#include "capwap.h"
/* */ /* */
struct nlsmartcapwap_device { struct sc_netlink_device {
struct list_head list; struct list_head list;
struct ieee80211_pcktunnel pcktunnel_handler; struct ieee80211_pcktunnel pcktunnel_handler;
u32 usermodeid; uint32_t ifindex;
u32 ifindex; uint8_t radioid;
u32 flags; uint8_t wlanid;
uint8_t binding;
struct net_device* dev;
uint32_t flags;
}; };
/* */ /* */
static u32 nlsmartcapwap_usermodeid = 0; static uint32_t sc_netlink_usermodeid;
static LIST_HEAD(nlsmartcapwap_dev_list); static LIST_HEAD(sc_netlink_dev_list);
/* */ /* */
static int nlsmartcapwap_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { static int sc_netlink_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_pre_doit\n");
rtnl_lock(); rtnl_lock();
return 0; return 0;
} }
/* */ /* */
static void nlsmartcapwap_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { static void sc_netlink_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_post_doit\n");
rtnl_unlock(); rtnl_unlock();
} }
/* Netlink Family */ /* Netlink Family */
static struct genl_family nlsmartcapwap_family = { static struct genl_family sc_netlink_family = {
.id = GENL_ID_GENERATE, .id = GENL_ID_GENERATE,
.name = SMARTCAPWAP_GENL_NAME, .name = NLSMARTCAPWAP_GENL_NAME,
.hdrsize = 0, .hdrsize = 0,
.version = 1, .version = 1,
.maxattr = NLSMARTCAPWAP_ATTR_MAX, .maxattr = NLSMARTCAPWAP_ATTR_MAX,
.netnsok = true, .netnsok = true,
.pre_doit = nlsmartcapwap_pre_doit, .pre_doit = sc_netlink_pre_doit,
.post_doit = nlsmartcapwap_post_doit, .post_doit = sc_netlink_post_doit,
}; };
/* */ /* */
static int nlsmartcapwap_handler(u32 ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) { static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) {
int result = 0; int ret = 0;
int frame8023 = 0; struct sc_netlink_device* nldev = (struct sc_netlink_device*)data;
struct nlsmartcapwap_device* nldev = (struct nlsmartcapwap_device*)data;
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data;
TRACEKMOD("### sc_netlink_handler\n");
/* IEEE802.11 Data Packet */ /* IEEE802.11 Data Packet */
if (ieee80211_is_data(hdr->frame_control)) { if (ieee80211_is_data(hdr->frame_control)) {
if ((nldev->flags & SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME) && ieee80211_is_data_present(hdr->frame_control)) { int err;
result = -1; struct sc_capwap_session* session;
unsigned char radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_radio_addr* radioaddr = NULL;
struct sc_capwap_wireless_information* winfo = NULL;
printk("*** receive packet\n");
/* Drop packet */
ret = -1;
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
goto error;
} }
/* Convert IEEE802.11 to IEEE802.3 */ /* IEEE 802.11 into IEEE 802.3 */
if (nldev->flags & SMARTCAPWAP_FLAGS_TUNNEL_8023) { if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) {
frame8023 = 1; if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) {
} printk("*** convertion error\n");
} goto error;
/* */
if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) {
void* msg;
struct sk_buff* sk_msg;
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (sk_msg) {
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &nlsmartcapwap_family, 0, NLSMARTCAPWAP_CMD_FRAME);
if (msg) {
/* Set params */
if (nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_IFINDEX, nldev->ifindex) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_FRAME, skb->len, skb->data) ||
(frame8023 && nla_put_flag(sk_msg, NLSMARTCAPWAP_ATTR_8023_FRAME)) ||
(sig_dbm && nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM, (u32)sig_dbm)) ||
(rate && nla_put_u8(sk_msg, NLSMARTCAPWAP_ATTR_RX_RATE, (u8)rate))) {
/* Abort message */
genlmsg_cancel(sk_msg, msg);
nlmsg_free(sk_msg);
} else {
/* Send message */
genlmsg_end(sk_msg, msg);
genlmsg_unicast(&init_net, sk_msg, nldev->usermodeid);
}
} else {
nlmsg_free(sk_msg);
} }
/* Create Radio Mac Address */
radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, nldev->dev->dev_addr);
} }
/* Create Wireless Information */
if (sig_dbm || rate) {
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
}
/* */
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211;
/* Forward to AC */
err = sc_capwap_forwarddata(session, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
printk("*** send: %d\n", err);
} }
return result; error:
return ret;
} }
/* */ /* */
static struct nlsmartcapwap_device* nlsmartcapwap_new_device(u32 ifindex) { static struct sc_netlink_device* sc_netlink_new_device(uint32_t ifindex, uint8_t radioid, u8 wlanid, uint8_t binding) {
struct nlsmartcapwap_device* nldev; struct net_device* dev;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_new_device\n");
/* Retrieve device from ifindex */
dev = dev_get_by_index(&init_net, ifindex);
if (!dev) {
return NULL;
}
/* Check if wireless device */
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
dev_put(dev);
return NULL;
}
/* Create device */ /* Create device */
nldev = (struct nlsmartcapwap_device*)kzalloc(sizeof(struct nlsmartcapwap_device), GFP_KERNEL); nldev = (struct sc_netlink_device*)kzalloc(sizeof(struct sc_netlink_device), GFP_KERNEL);
if (nldev) { if (!nldev) {
/* Initialize device */ dev_put(dev);
nldev->pcktunnel_handler.handler = nlsmartcapwap_handler; return NULL;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
} }
/* Initialize device */
nldev->pcktunnel_handler.handler = sc_netlink_handler;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
nldev->radioid = radioid;
nldev->wlanid = wlanid;
nldev->binding = binding;
nldev->dev = dev;
return nldev; return nldev;
} }
/* */ /* */
static void nlsmartcapwap_free_device(struct nlsmartcapwap_device* nldev) { static void sc_netlink_free_device(struct sc_netlink_device* nldev) {
TRACEKMOD("### sc_netlink_free_device\n");
/* Disconnect device from mac80211 */ /* Disconnect device from mac80211 */
ieee80211_pcktunnel_deregister(nldev->ifindex, &nldev->pcktunnel_handler); ieee80211_pcktunnel_deregister(nldev->dev, &nldev->pcktunnel_handler);
/* */
dev_put(nldev->dev);
/* Free memory */ /* Free memory */
kfree(nldev); kfree(nldev);
} }
/* */ /* */
static struct nlsmartcapwap_device* nlsmartcapwap_register_device(u32 ifindex) { static struct sc_netlink_device* sc_netlink_register_device(uint32_t ifindex, uint8_t radioid, uint16_t wlanid, uint8_t binding) {
struct nlsmartcapwap_device* nldev; struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_register_device\n");
ASSERT_RTNL(); ASSERT_RTNL();
/* */
if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) {
return NULL;
}
/* Search device */ /* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) { list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
if (nldev->ifindex == ifindex) { if (nldev->ifindex == ifindex) {
return nldev; return NULL;
} }
} }
/* Create device */ /* Create device */
nldev = nlsmartcapwap_new_device(ifindex); nldev = sc_netlink_new_device(ifindex, radioid, wlanid, binding);
if (nldev) { if (nldev) {
list_add_rcu(&nldev->list, &nlsmartcapwap_dev_list); list_add_rcu(&nldev->list, &sc_netlink_dev_list);
} }
return nldev; return nldev;
} }
/* */ /* */
static int nlsmartcapwap_unregister_device(u32 ifindex) { static int sc_netlink_unregister_device(uint32_t ifindex) {
int ret = -ENODEV; int ret = -ENODEV;
struct nlsmartcapwap_device* nldev; struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_unregister_device\n");
ASSERT_RTNL(); ASSERT_RTNL();
/* Search device */ /* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) { list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
if (nldev->ifindex == ifindex) { if (nldev->ifindex == ifindex) {
/* Remove from list */ /* Remove from list */
list_del_rcu(&nldev->list); list_del_rcu(&nldev->list);
@ -163,7 +211,7 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
/* Free device */ /* Free device */
ret = 0; ret = 0;
nlsmartcapwap_free_device(nldev); sc_netlink_free_device(nldev);
break; break;
} }
} }
@ -172,27 +220,43 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
} }
/* */ /* */
static void nlsmartcapwap_close(void) { static void sc_netlink_unregister_alldevice(void) {
struct nlsmartcapwap_device* nldev; struct sc_netlink_device* tmp;
struct nlsmartcapwap_device* tmp; struct sc_netlink_device* nldev;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_dev_list, list) { TRACEKMOD("### sc_netlink_unregister_alldevice\n");
list_del(&nldev->list);
ASSERT_RTNL();
/* Close all devices */
list_for_each_entry_safe(nldev, tmp, &sc_netlink_dev_list, list) {
/* Remove from list */
list_del_rcu(&nldev->list);
synchronize_net();
/* Free device */ /* Free device */
nlsmartcapwap_free_device(nldev); sc_netlink_free_device(nldev);
} }
} }
/* */ /* */
static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) { static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0; int ret;
u32 portid = genl_info_snd_portid(info); uint32_t portid = genl_info_snd_portid(info);
if (!nlsmartcapwap_usermodeid) { TRACEKMOD("### sc_netlink_link\n");
nlsmartcapwap_usermodeid = portid;
} else if (nlsmartcapwap_usermodeid == portid) { if (!sc_netlink_usermodeid) {
/* Initialize library */
ret = sc_capwap_init(1);
if (!ret) {
sc_netlink_usermodeid = portid;
/* Deny unload module */
try_module_get(THIS_MODULE);
}
} else if (sc_netlink_usermodeid == portid) {
ret = -EALREADY; ret = -EALREADY;
} else { } else {
ret = -EBUSY; ret = -EBUSY;
@ -202,19 +266,39 @@ static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) {
} }
/* */ /* */
static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info) {
struct netlink_notify* notify = (struct netlink_notify*)_notify; /* Check Link */
u32 portid = netlink_notify_portid(notify); if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Close all devices */
sc_netlink_unregister_alldevice();
/* Reset session */
sc_capwap_resetsession();
return 0;
}
/* */
static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
struct netlink_notify* notify = (struct netlink_notify*)_notify;
/* */
if (state == NETLINK_URELEASE) { if (state == NETLINK_URELEASE) {
rtnl_lock(); rtnl_lock();
if (nlsmartcapwap_usermodeid == portid) { if (sc_netlink_usermodeid == netlink_notify_portid(notify)) {
nlsmartcapwap_usermodeid = 0; sc_netlink_usermodeid = 0;
/* Close all devices */ /* Close all devices */
nlsmartcapwap_close(); sc_netlink_unregister_alldevice();
/* Close capwap engine */
sc_capwap_close();
/* Allow unload module */
module_put(THIS_MODULE);
} }
rtnl_unlock(); rtnl_unlock();
@ -224,10 +308,194 @@ static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long
} }
/* */ /* */
static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) { static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex; union capwap_addr sockaddr;
struct nlsmartcapwap_device* nldev;
int ret = -EINVAL; TRACEKMOD("### sc_netlink_bind\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(&sockaddr);
}
/* */
static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info) {
int ret;
union capwap_addr sockaddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_connect\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get AC address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) {
return -EINVAL;
}
}
/* Get Session ID */
if (info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) == sizeof(struct sc_capwap_sessionid_element))) {
memcpy(sessionid.id, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element));
} else {
return -EINVAL;
}
/* Send packet */
ret = sc_capwap_connect(&sockaddr, &sessionid, mtu);
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) {
int ret;
TRACEKMOD("### sc_netlink_send_keepalive\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Send packet */
ret = sc_capwap_sendkeepalive();
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint8_t radioid;
uint8_t binding;
uint8_t rssi = 0;
uint8_t snr = 0;
uint16_t rate = 0;
int length;
struct sk_buff* skbdata;
struct sc_capwap_session* session;
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_wireless_information* winfo = NULL;
TRACEKMOD("### sc_netlink_send_data\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
} else if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
return -EINVAL;
}
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
return -ENOLINK;
}
/* Get radioid */
radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
if (!IS_VALID_RADIOID(radioid) || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
return -EINVAL;
}
/* Get binding */
binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]);
/* Get RSSI */
if (info->attrs[NLSMARTCAPWAP_ATTR_RSSI]) {
rssi = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RSSI]);
}
/* Get SNR */
if (info->attrs[NLSMARTCAPWAP_ATTR_SNR]) {
snr = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_SNR]);
}
/* Get RATE */
if (info->attrs[NLSMARTCAPWAP_ATTR_RATE]) {
rate = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RATE]);
}
/* Create Wireless Information */
if (rssi || snr || rate) {
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate);
}
/* Create socket buffer */
length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]);
skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL);
if (!skbdata) {
return -ENOMEM;
}
/* Reserve space for Capwap Header */
skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH);
/* Copy data into socket buffer */
memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length);
/* */
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE;
/* Send packet */
ret = sc_capwap_forwarddata(session, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
if (ret) {
TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n");
}
kfree_skb(skbdata);
return ret;
}
/* */
static int sc_netlink_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint32_t ifindex;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_join_mac80211_device\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get interface index */ /* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
@ -239,8 +507,13 @@ static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_i
return -EINVAL; return -EINVAL;
} }
/* Check */
if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
return -EINVAL;
}
/* Register device */ /* Register device */
nldev = nlsmartcapwap_register_device(ifindex); nldev = sc_netlink_register_device(ifindex, nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]));
if (!nldev) { if (!nldev) {
return -EINVAL; return -EINVAL;
} }
@ -263,106 +536,240 @@ static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_i
nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]); nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]);
} }
/* */
if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) {
nldev->usermodeid = genl_info_snd_portid(info);
}
/* Connect device to mac80211 */ /* Connect device to mac80211 */
ret = ieee80211_pcktunnel_register(ifindex, &nldev->pcktunnel_handler); ret = ieee80211_pcktunnel_register(nldev->dev, &nldev->pcktunnel_handler);
if (ret) { if (ret) {
nlsmartcapwap_unregister_device(ifindex); sc_netlink_unregister_device(ifindex);
} }
return ret; return ret;
} }
/* */ /* */
static int nlsmartcapwap_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) { static int sc_netlink_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex; TRACEKMOD("### sc_netlink_leave_mac80211_device\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get interface index */ /* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
return -EINVAL; return -EINVAL;
} }
ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]);
if (!ifindex) {
return -EINVAL;
}
/* Unregister device */ /* Unregister device */
return nlsmartcapwap_unregister_device(ifindex); return sc_netlink_unregister_device(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]));
} }
/* */ /* */
static const struct nla_policy nlsmartcapwap_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = { static int sc_device_event(struct notifier_block* unused, unsigned long event, void* ptr) {
struct net_device* dev = netdev_notifier_info_to_dev(ptr);
/* Check event only if connect with WTP userspace */
if (!sc_netlink_usermodeid) {
return NOTIFY_DONE;
}
/* */
switch (event) {
case NETDEV_UNREGISTER: {
/* Try to unregister device */
sc_netlink_unregister_device(dev->ifindex);
break;
}
}
return NOTIFY_DONE;
}
/* */
static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 }, [NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 }, [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 }, [NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 }, [NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 }, [NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, [NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_8023_FRAME] = { .type = NLA_FLAG }, [NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] = { .type = NLA_U32 }, [NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_RX_RATE] = { .type = NLA_U8 }, [NLSMARTCAPWAP_ATTR_DTLS] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MTU },
[NLSMARTCAPWAP_ATTR_RSSI] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_SNR] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_RATE] = { .type = NLA_U16 },
}; };
/* Netlink Ops */ /* Netlink Ops */
static __genl_const struct genl_ops nlsmartcapwap_ops[] = { static __genl_const struct genl_ops sc_netlink_ops[] = {
{ {
.cmd = NLSMARTCAPWAP_CMD_LINK, .cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = nlsmartcapwap_link, .doit = sc_netlink_link,
.policy = nlsmartcapwap_policy, .policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_BIND,
.doit = sc_netlink_bind,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_CONNECT,
.doit = sc_netlink_connect,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_RESET,
.doit = sc_netlink_reset,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
.doit = sc_netlink_send_keepalive,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_DATA,
.doit = sc_netlink_send_data,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
{ {
.cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, .cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
.doit = nlsmartcapwap_join_mac80211_device, .doit = sc_netlink_join_mac80211_device,
.policy = nlsmartcapwap_policy, .policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
{ {
.cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, .cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
.doit = nlsmartcapwap_leave_mac80211_device, .doit = sc_netlink_leave_mac80211_device,
.policy = nlsmartcapwap_policy, .policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
}; };
/* Netlink notify */ /* Netlink notify */
static struct notifier_block nlsmartcapwap_netlink_notifier = { static struct notifier_block sc_netlink_notifier = {
.notifier_call = nlsmartcapwap_netlink_notify, .notifier_call = sc_netlink_notify,
};
/* Interface notify */
struct notifier_block sc_device_notifier = {
.notifier_call = sc_device_event
}; };
/* */ /* */
int nlsmartcapwap_init(void) { int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_keepalive\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE);
if (!msg) {
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
}
/* */
int sc_netlink_notify_recv_data(uint8_t* packet, int length) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_data\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_init(void) {
int ret; int ret;
/* Register netlink family */ TRACEKMOD("### sc_netlink_init\n");
ret = genl_register_family_with_ops(&nlsmartcapwap_family, nlsmartcapwap_ops);
/* */
sc_netlink_usermodeid = 0;
/* Register interface event */
ret = register_netdevice_notifier(&sc_device_notifier);
if (ret) { if (ret) {
return ret; goto error;
}
/* Register netlink family */
ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops);
if (ret) {
goto error2;
} }
/* Register netlink notifier */ /* Register netlink notifier */
ret = netlink_register_notifier(&nlsmartcapwap_netlink_notifier); ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) { if (ret) {
genl_unregister_family(&nlsmartcapwap_family); goto error3;
return ret;
} }
return 0;
error3:
genl_unregister_family(&sc_netlink_family);
error2:
unregister_netdevice_notifier(&sc_device_notifier);
error:
return ret; return ret;
} }
/* */ /* */
void nlsmartcapwap_exit(void) { void sc_netlink_exit(void) {
/* */ TRACEKMOD("### sc_netlink_exit\n");
rtnl_lock();
nlsmartcapwap_close();
rtnl_unlock();
/* */ netlink_unregister_notifier(&sc_netlink_notifier);
netlink_unregister_notifier(&nlsmartcapwap_netlink_notifier); genl_unregister_family(&sc_netlink_family);
genl_unregister_family(&nlsmartcapwap_family); unregister_netdevice_notifier(&sc_device_notifier);
} }

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_CAPWAP_NETLINKAPP_HEADER__ #ifndef __KMOD_WTP_NETLINKAPP_HEADER__
#define __KMOD_CAPWAP_NETLINKAPP_HEADER__ #define __KMOD_WTP_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */ /* */
int nlsmartcapwap_init(void); int sc_netlink_init(void);
void nlsmartcapwap_exit(void); void sc_netlink_exit(void);
#endif /* __KMOD_CAPWAP_NETLINKAPP_HEADER__ */ /* */
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(uint8_t* packet, int length);
#endif /* __KMOD_WTP_NETLINKAPP_HEADER__ */

View File

@ -1,19 +1,20 @@
#ifndef __CAPWAP_NLSMARTCAPWAP_HEADER__ #ifndef __WTP_NLSMARTCAPWAP_HEADER__
#define __CAPWAP_NLSMARTCAPWAP_HEADER__ #define __WTP_NLSMARTCAPWAP_HEADER__
/* */ /* */
#define SMARTCAPWAP_GENL_NAME "smartcapwap" #define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp"
/* */ /* */
#define SMARTCAPWAP_FLAGS_SEND_USERSPACE 0x00000001 #define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
#define SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME 0x00000002
#define SMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000004
/* */ /* */
enum nlsmartcapwap_attrs { enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC, NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_IFINDEX, NLSMARTCAPWAP_ATTR_IFINDEX,
NLSMARTCAPWAP_ATTR_RADIOID,
NLSMARTCAPWAP_ATTR_WLANID,
NLSMARTCAPWAP_ATTR_BINDING,
NLSMARTCAPWAP_ATTR_FLAGS, NLSMARTCAPWAP_ATTR_FLAGS,
@ -21,10 +22,17 @@ enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_FRAME, NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_8023_FRAME, NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM,
NLSMARTCAPWAP_ATTR_RX_RATE, NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_DTLS,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_RSSI,
NLSMARTCAPWAP_ATTR_SNR,
NLSMARTCAPWAP_ATTR_RATE,
/* Last attribute */ /* Last attribute */
__NLSMARTCAPWAP_ATTR_AFTER_LAST, __NLSMARTCAPWAP_ATTR_AFTER_LAST,
@ -37,14 +45,15 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_LINK, NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_SET_AC_ADDRESS, NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_CONNECT, NLSMARTCAPWAP_CMD_CONNECT,
NLSMARTCAPWAP_CMD_TEARDOWN, NLSMARTCAPWAP_CMD_RESET,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_FRAME, NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
@ -54,4 +63,4 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1 NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
}; };
#endif /* __CAPWAP_NLSMARTCAPWAP_HEADER__ */ #endif /* __WTP_NLSMARTCAPWAP_HEADER__ */

257
src/wtp/kmod/socket.c Normal file
View File

@ -0,0 +1,257 @@
#include "config.h"
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/kthread.h>
#include <linux/net.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <net/ipv6.h>
#include <net/sock.h>
#include <net/udp.h>
#include "socket.h"
#include "capwap.h"
/* Socket */
#define SOCKET_COUNT 2
static struct socket* sc_sockets[SOCKET_COUNT];
/* */
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_socket_recvpacket\n");
/* */
cb->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
/* */
sc_capwap_recvpacket(skb);
return 0;
}
/* */
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
int ret;
TRACEKMOD("### sc_socket_create\n");
/* Create socket */
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
if (ret) {
goto failure;
}
/* Bind to interface */
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
if (ret) {
goto failure2;
}
/* Set callback */
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
/* */
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
union capwap_addr localaddr;
int localaddrsize = sizeof(union capwap_addr);
/* Retrieve port */
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
if (ret) {
goto failure2;
}
/* */
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
sockaddr->sin.sin_port = localaddr.sin.sin_port;
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
} else {
ret = -EFAULT;
goto failure2;
}
}
return ret;
failure2:
sock_release(sc_sockets[type]);
sc_sockets[type] = 0;
failure:
return ret;
}
/* */
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
unsigned char* nethdr;
TRACEKMOD("### sc_socket_getpeeraddr\n");
/* */
nethdr = skb_network_header(skb);
if (!nethdr) {
return -EINVAL;
}
/* */
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {
/* Validate IPv4 header */
if ((nethdr[0] & 0xf0) != 0x40) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin.sin_family = AF_INET;
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
peeraddr->sin.sin_port = udp_hdr(skb)->source;
break;
}
case ETH_P_IPV6: {
/* Validate IPv6 header */
if ((nethdr[0] & 0xf0) != 0x60) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin6.sin6_family = AF_INET6;
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
break;
}
default: {
return -EINVAL;
}
}
return 0;
}
/* */
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
struct kvec vec;
struct msghdr msg;
TRACEKMOD("### sc_socket_send\n");
/* */
vec.iov_base = buffer;
vec.iov_len = length;
/* */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = sockaddr;
msg.msg_namelen = sizeof(union capwap_addr);
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
/* */
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
}
/* */
int sc_socket_init(void) {
TRACEKMOD("### sc_socket_init\n");
memset(sc_sockets, 0, sizeof(sc_sockets));
return 0;
}
/* */
int sc_socket_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_socket_bind\n");
/* */
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
return -EBUSY;
}
/* UDP socket */
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
if (ret) {
goto failure;
}
/* UDPLite socket */
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
if (ret) {
goto failure;
}
/* */
udp_encap_enable();
if (sockaddr->ss.ss_family == AF_INET6) {
udpv6_encap_enable();
}
return 0;
failure:
sc_socket_close();
return ret;
}
/* */
void sc_socket_close(void) {
TRACEKMOD("### sc_socket_close\n");
/* Close sockets */
if (sc_sockets[SOCKET_UDP]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDP]);
}
if (sc_sockets[SOCKET_UDPLITE]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDPLITE]);
}
memset(sc_sockets, 0, sizeof(sc_sockets));
}
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
TRACEKMOD("### sc_addr_compare\n");
if (addr1->ss.ss_family == addr2->ss.ss_family) {
if (addr1->ss.ss_family == AF_INET) {
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
} else if (addr1->ss.ss_family == AF_INET6) {
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
}
}
return -1;
}
/* */
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little) {
little->family = (uint8_t)addr->ss.ss_family;
if (little->family == AF_INET) {
memcpy(&little->addr4, &addr->sin.sin_addr, sizeof(struct in_addr));
little->port = addr->sin.sin_port;
} else if (little->family == AF_INET6) {
memcpy(&little->addr6, &addr->sin6.sin6_addr, sizeof(struct in6_addr));
little->port = addr->sin6.sin6_port;
}
}
/* */
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr) {
memset(addr, 0, sizeof(union capwap_addr));
addr->ss.ss_family = little->family;
if (little->family == AF_INET) {
memcpy(&addr->sin.sin_addr, &little->addr4, sizeof(struct in_addr));
addr->sin.sin_port = little->port;
} else if (little->family == AF_INET6) {
memcpy(&addr->sin6.sin6_addr, &little->addr6, sizeof(struct in6_addr));
addr->sin6.sin6_port = little->port;
}
}

45
src/wtp/kmod/socket.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __KMOD_SOCKET_HEADER__
#define __KMOD_SOCKET_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
/* */
#define SOCKET_UDP 0
#define SOCKET_UDPLITE 1
/* Little socket address */
struct capwap_addr_little {
uint8_t family;
union {
struct in_addr addr4;
struct in6_addr addr6;
};
uint16_t port;
};
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
/* */
int sc_socket_init(void);
void sc_socket_close(void);
/* */
int sc_socket_bind(union capwap_addr* sockaddr);
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little);
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr);
#endif /* __KMOD_SOCKET_HEADER__ */

View File

@ -62,7 +62,6 @@ static int wtp_init(void) {
g_wtp.mactype.type = CAPWAP_LOCALMAC; g_wtp.mactype.type = CAPWAP_LOCALMAC;
g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING; g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE;
/* DTLS */ /* DTLS */
g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED; g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
@ -76,8 +75,8 @@ static int wtp_init(void) {
/* AC information */ /* AC information */
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN; g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN;
g_wtp.acdiscoveryrequest = 1; g_wtp.acdiscoveryrequest = 1;
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(struct sockaddr_storage), 0, 0); g_wtp.acdiscoveryarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
g_wtp.acpreferedarray = capwap_array_create(sizeof(struct sockaddr_storage), 0, 0); g_wtp.acpreferedarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1); g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1);
/* Radios */ /* Radios */
@ -135,48 +134,22 @@ static void wtp_destroy(void) {
wtp_radio_free(); wtp_radio_free();
} }
/* Save AC address */
static int wtp_add_acaddress(struct sockaddr_storage* source, struct capwap_array* array) {
ASSERT(source != NULL);
ASSERT(array != NULL);
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == source->ss_family)) {
struct sockaddr_storage* destaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(array, array->count);
/* Save address, if request, mapping IPv4 to IPv6 */
if ((g_wtp.net.sock_family == AF_UNSPEC) && (source->ss_family == AF_INET) && !(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG)) {
if (!capwap_ipv4_mapped_ipv6(source, destaddr)) {
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
}
} else {
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
}
return 1;
}
return 0;
}
/* */ /* */
static int wtp_add_default_acaddress() { static void wtp_add_default_acaddress() {
struct sockaddr_storage address; union sockaddr_capwap address;
struct sockaddr_in* addressv4 = (struct sockaddr_in*)&address;
/*struct sockaddr_in6* addressv6 = (struct sockaddr_in6*)&address;*/
/* Broadcast IPv4 */ /* Broadcast IPv4 */
addressv4->sin_family = AF_INET; memset(&address, 0, sizeof(union sockaddr_capwap));
addressv4->sin_addr.s_addr = INADDR_BROADCAST; address.sin.sin_family = AF_INET;
addressv4->sin_port = htons(CAPWAP_CONTROL_PORT); address.sin.sin_addr.s_addr = INADDR_BROADCAST;
wtp_add_acaddress(&address, g_wtp.acdiscoveryarray); address.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &address, sizeof(union sockaddr_capwap));
/* Multicast IPv4 */ /* Multicast IPv4 */
/* TODO */ /* TODO */
/* Multicast IPv6 */ /* Multicast IPv6 */
/* TODO */ /* TODO */
return ((g_wtp.acdiscoveryarray->count > 0) ? 1 : 0);
} }
/* Help */ /* Help */
@ -514,8 +487,6 @@ static int wtp_parsing_radio_configuration(config_setting_t* configElement, stru
static int wtp_parsing_configuration_1_0(config_t* config) { static int wtp_parsing_configuration_1_0(config_t* config) {
int i; int i;
int configBool; int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt; LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString; const char* configString;
config_setting_t* configSetting; config_setting_t* configSetting;
@ -651,19 +622,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING; g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING;
} }
} }
if (config_lookup_string(config, "application.tunnelmode.dataframe", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "none")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_NONE;
} else if (!strcmp(configString, "kernelmode")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE;
} else if (!strcmp(configString, "usermode")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_USERMODE;
} else {
capwap_logging_error("Invalid configuration file, unknown application.tunnelmode.dataframe value");
return 0;
}
}
} }
/* Set mactype of WTP */ /* Set mactype of WTP */
@ -1094,7 +1052,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
return 0; return 0;
} }
strcpy(g_wtp.net.bind_interface, configString); strcpy(g_wtp.net.bindiface, configString);
} }
/* Set mtu of WTP */ /* Set mtu of WTP */
@ -1107,16 +1065,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
} }
} }
/* Set network port of WTP */
if (config_lookup_int(config, "application.network.port", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65535)) {
g_wtp.net.bind_sock_ctrl_port = (unsigned short)configInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.network.port value");
return 0;
}
}
/* Set transport of WTP */ /* Set transport of WTP */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) { if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) { if (!strcmp(configString, "udp")) {
@ -1129,35 +1077,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
} }
} }
/* Set ipv4 & ipv6 of WTP */
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_wtp.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_wtp.net.sock_family = (configIPv4 ? AF_INET : AF_INET6);
}
/* Set ip dual stack of WTP */
if (config_lookup_bool(config, "application.network.ipdualstack", &configBool) == CONFIG_TRUE) {
if (!configBool) {
g_wtp.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG;
g_wtp.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG;
} else {
g_wtp.net.bind_ctrl_flags &= ~CAPWAP_IPV6ONLY_FLAG;
g_wtp.net.bind_data_flags &= ~CAPWAP_IPV6ONLY_FLAG;
}
}
/* Set search discovery of WTP */ /* Set search discovery of WTP */
if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) { if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) {
g_wtp.acdiscoveryrequest = (configBool ? 1 : 0); g_wtp.acdiscoveryrequest = (configBool ? 1 : 0);
@ -1167,19 +1086,19 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
configSetting = config_lookup(config, "application.acdiscovery.host"); configSetting = config_lookup(config, "application.acdiscovery.host");
if (configSetting != NULL) { if (configSetting != NULL) {
int count = config_setting_length(configSetting); int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i); const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) { if (address != NULL) {
struct sockaddr_storage acaddr; union sockaddr_capwap acaddr;
/* Parsing address */ /* Parsing address */
if (capwap_address_from_string(address, &acaddr)) { if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) { if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT); CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
} }
wtp_add_acaddress(&acaddr, g_wtp.acdiscoveryarray); memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &acaddr, sizeof(union sockaddr_capwap));
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_STATIC; g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_STATIC;
} else { } else {
capwap_logging_error("Invalid configuration file, invalid application.acdiscovery.host value"); capwap_logging_error("Invalid configuration file, invalid application.acdiscovery.host value");
@ -1193,19 +1112,19 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
configSetting = config_lookup(config, "application.acprefered.host"); configSetting = config_lookup(config, "application.acprefered.host");
if (configSetting != NULL) { if (configSetting != NULL) {
int count = config_setting_length(configSetting); int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i); const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) { if (address != NULL) {
struct sockaddr_storage acaddr; union sockaddr_capwap acaddr;
/* Parsing address */ /* Parsing address */
if (capwap_address_from_string(address, &acaddr)) { if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) { if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT); CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
} }
wtp_add_acaddress(&acaddr, g_wtp.acpreferedarray); memcpy(capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedarray->count), &acaddr, sizeof(union sockaddr_capwap));
} else { } else {
capwap_logging_error("Invalid configuration file, invalid application.acprefered.host value"); capwap_logging_error("Invalid configuration file, invalid application.acprefered.host value");
return 0; return 0;
@ -1294,17 +1213,25 @@ static int wtp_load_configuration(int argc, char **argv) {
/* Init WTP */ /* Init WTP */
static int wtp_configure(void) { static int wtp_configure(void) {
/* If not set try IPv6 */
if (g_wtp.net.localaddr.ss.ss_family == AF_UNSPEC) {
g_wtp.net.localaddr.ss.ss_family = AF_INET6;
}
/* If request add default acdiscovery */ /* If request add default acdiscovery */
if (!g_wtp.acdiscoveryarray->count) { if (!g_wtp.acdiscoveryarray->count) {
if (!wtp_add_default_acaddress()) { wtp_add_default_acaddress();
capwap_logging_debug("Unable add default AC discovery");
return WTP_ERROR_NETWORK;
}
} }
/* Bind to any address */ /* Bind control address */
if (!capwap_bind_sockets(&g_wtp.net)) { if (capwap_bind_sockets(&g_wtp.net)) {
capwap_logging_fatal("Cannot bind address"); capwap_logging_fatal("Cannot bind control address");
return WTP_ERROR_NETWORK;
}
/* Bind data address */
if (wtp_kmod_bind(g_wtp.net.localaddr.ss.ss_family)) {
capwap_logging_fatal("Cannot bind data address");
return WTP_ERROR_NETWORK; return WTP_ERROR_NETWORK;
} }
@ -1396,11 +1323,8 @@ int main(int argc, char** argv) {
wtp_wait_radio_ready(); wtp_wait_radio_ready();
/* Connect WTP with kernel module */ /* Connect WTP with kernel module */
value = wtp_kmod_init(); if (!wtp_kmod_init()) {
if (!value || !g_wtp.kmodrequest) { capwap_logging_info("SmartCAPWAP kernel module connected");
if (wtp_kmod_isconnected()) {
capwap_logging_info("SmartCAPWAP kernel module connected");
}
/* */ /* */
capwap_logging_info("Startup WTP"); capwap_logging_info("Startup WTP");
@ -1411,7 +1335,7 @@ int main(int argc, char** argv) {
/* Running WTP */ /* Running WTP */
result = wtp_dfa_running(); result = wtp_dfa_running();
/* Close socket */ /* Close sockets */
capwap_close_sockets(&g_wtp.net); capwap_close_sockets(&g_wtp.net);
} }

View File

@ -68,13 +68,13 @@ struct wtp_t {
int running; int running;
/* */ /* */
int kmodrequest;
struct wtp_kmod_handle kmodhandle; struct wtp_kmod_handle kmodhandle;
/* */ /* */
char wlanprefix[IFNAMSIZ]; char wlanprefix[IFNAMSIZ];
/* */ /* */
unsigned short mtu;
struct capwap_network net; struct capwap_network net;
struct wtp_fds fds; struct wtp_fds fds;
@ -113,21 +113,20 @@ struct wtp_t {
struct capwap_statisticstimer_element statisticstimer; struct capwap_statisticstimer_element statisticstimer;
struct capwap_wtprebootstat_element rebootstat; struct capwap_wtprebootstat_element rebootstat;
int tunneldataframe; /* */
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngctrlpacket; struct capwap_packet_rxmng* rxmngpacket;
struct capwap_packet_rxmng* rxmngdatapacket;
/* */ /* */
unsigned char localseqnumber; uint8_t localseqnumber;
unsigned char remoteseqnumber;
unsigned short mtu;
unsigned short fragmentid;
struct capwap_list* requestfragmentpacket; struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount; int retransmitcount;
/* */
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
/* */ /* */
int acdiscoveryrequest; int acdiscoveryrequest;
unsigned long acpreferedselected; unsigned long acpreferedselected;
@ -135,13 +134,6 @@ struct wtp_t {
struct capwap_array* acpreferedarray; struct capwap_array* acpreferedarray;
struct capwap_array* acdiscoveryresponse; struct capwap_array* acdiscoveryresponse;
struct sockaddr_storage wtpctrladdress;
struct sockaddr_storage wtpdataaddress;
struct sockaddr_storage acctrladdress;
struct sockaddr_storage acdataaddress;
struct capwap_socket acctrlsock;
struct capwap_socket acdatasock;
/* */ /* */
struct capwap_array* radios; struct capwap_array* radios;
@ -154,8 +146,7 @@ struct wtp_t {
unsigned char dtlsdatapolicy; unsigned char dtlsdatapolicy;
unsigned char validdtlsdatapolicy; unsigned char validdtlsdatapolicy;
struct capwap_dtls_context dtlscontext; struct capwap_dtls_context dtlscontext;
struct capwap_dtls ctrldtls; struct capwap_dtls dtls;
struct capwap_dtls datadtls;
int faileddtlssessioncount; int faileddtlssessioncount;
int faileddtlsauthfailcount; int faileddtlsauthfailcount;
}; };

View File

@ -17,39 +17,24 @@ static void wtp_signal_handler(int signum) {
} }
/* */ /* */
static struct capwap_packet_rxmng* wtp_get_packet_rxmng(int isctrlmsg) { static struct capwap_packet_rxmng* wtp_get_packet_rxmng(void) {
struct capwap_packet_rxmng* rxmngpacket = NULL; if (!g_wtp.rxmngpacket) {
g_wtp.rxmngpacket = capwap_packet_rxmng_create_message();
if (isctrlmsg) {
if (!g_wtp.rxmngctrlpacket) {
g_wtp.rxmngctrlpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET);
}
rxmngpacket = g_wtp.rxmngctrlpacket;
} else {
if (!g_wtp.rxmngdatapacket) {
g_wtp.rxmngdatapacket = capwap_packet_rxmng_create_message(CAPWAP_DATA_PACKET);
}
rxmngpacket = g_wtp.rxmngdatapacket;
} }
return rxmngpacket; return g_wtp.rxmngpacket;
} }
/* */ /* */
void wtp_free_packet_rxmng(int isctrlmsg) { void wtp_free_packet_rxmng(void) {
if (isctrlmsg && g_wtp.rxmngctrlpacket) { if (g_wtp.rxmngpacket) {
capwap_packet_rxmng_free(g_wtp.rxmngctrlpacket); capwap_packet_rxmng_free(g_wtp.rxmngpacket);
g_wtp.rxmngctrlpacket = NULL; g_wtp.rxmngpacket = NULL;
} else if (!isctrlmsg && g_wtp.rxmngdatapacket) {
capwap_packet_rxmng_free(g_wtp.rxmngdatapacket);
g_wtp.rxmngdatapacket = NULL;
} }
} }
/* */ /* */
static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, uint32_t errorcode) { static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, uint32_t errorcode) {
struct capwap_header_data capwapheader; struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket; struct capwap_packet_txmng* txmngpacket;
struct capwap_list* responsefragmentpacket; struct capwap_list* responsefragmentpacket;
@ -59,7 +44,6 @@ static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, st
ASSERT(rxmngpacket != NULL); ASSERT(rxmngpacket != NULL);
ASSERT(rxmngpacket->fragmentlist->first != NULL); ASSERT(rxmngpacket->fragmentlist->first != NULL);
ASSERT(connection != NULL);
/* */ /* */
packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item; packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item;
@ -83,7 +67,7 @@ static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, st
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send unknown response */ /* Send unknown response */
capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, connection->socket.socket[connection->socket.type], responsefragmentpacket, &connection->localaddr, &connection->remoteaddr); capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, responsefragmentpacket);
/* Don't buffering a packets sent */ /* Don't buffering a packets sent */
capwap_list_free(responsefragmentpacket); capwap_list_free(responsefragmentpacket);
@ -142,7 +126,7 @@ static void wtp_dfa_execute(struct capwap_parsed_packet* packet) {
} }
/* */ /* */
static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) { static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, union sockaddr_capwap* recvfromaddr, union sockaddr_capwap* recvtoaddr) {
int index; int index;
ASSERT(fds != NULL); ASSERT(fds != NULL);
@ -185,7 +169,7 @@ static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct soc
} }
/* Receive packet */ /* Receive packet */
if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { if (capwap_recvfrom(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
return CAPWAP_RECV_ERROR_SOCKET; return CAPWAP_RECV_ERROR_SOCKET;
} }
@ -335,13 +319,11 @@ int wtp_dfa_running(void) {
char* buffer; char* buffer;
int buffersize; int buffersize;
struct capwap_socket socket;
struct capwap_connection connection;
struct capwap_parsed_packet packet; struct capwap_parsed_packet packet;
int index; int index;
struct sockaddr_storage recvfromaddr; union sockaddr_capwap fromaddr;
struct sockaddr_storage recvtoaddr; union sockaddr_capwap toaddr;
/* Init */ /* Init */
memset(&packet, 0, sizeof(struct capwap_parsed_packet)); memset(&packet, 0, sizeof(struct capwap_parsed_packet));
@ -366,79 +348,51 @@ int wtp_dfa_running(void) {
/* If request wait packet from AC */ /* If request wait packet from AC */
buffer = bufferencrypt; buffer = bufferencrypt;
buffersize = CAPWAP_MAX_PACKET_SIZE; buffersize = CAPWAP_MAX_PACKET_SIZE;
index = wtp_recvfrom(&g_wtp.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr); index = wtp_recvfrom(&g_wtp.fds, buffer, &buffersize, &fromaddr, &toaddr);
if (!g_wtp.running) { if (!g_wtp.running) {
capwap_logging_debug("Closing WTP, Teardown connection"); capwap_logging_debug("Closing WTP, Teardown connection");
wtp_dfa_closeapp(); wtp_dfa_closeapp();
break; break;
} else if (index >= 0) { } else if (index >= 0) {
if (g_wtp.teardown) { if (g_wtp.teardown) {
/* Drop packet */ continue; /* Drop packet */
continue;
} else { } else {
int check; int check;
/* Retrieve network information */
capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds.fdspoll[index].fd);
/* Check source */ /* Check source */
if (socket.isctrlsocket && (g_wtp.acctrladdress.ss_family != AF_UNSPEC)) { if (capwap_compare_ip(&g_wtp.dtls.peeraddr, &fromaddr)) {
if (capwap_compare_ip(&g_wtp.acctrladdress, &recvfromaddr)) { continue; /* Unknown source */
/* Unknown source */
continue;
}
} else if (!socket.isctrlsocket && (g_wtp.acdataaddress.ss_family != AF_UNSPEC)) {
if (capwap_compare_ip(&g_wtp.acdataaddress, &recvfromaddr)) {
/* Unknown source */
continue;
}
} }
/* Check of packet */ /* Check of packet */
check = capwap_sanity_check(socket.isctrlsocket, g_wtp.state, buffer, buffersize, g_wtp.ctrldtls.enable, g_wtp.datadtls.enable); check = capwap_sanity_check(g_wtp.state, buffer, buffersize, g_wtp.dtls.enable);
if (check == CAPWAP_DTLS_PACKET) { if (check == CAPWAP_DTLS_PACKET) {
struct capwap_dtls* dtls = (socket.isctrlsocket ? &g_wtp.ctrldtls : &g_wtp.datadtls); int oldaction = g_wtp.dtls.action;
if (dtls->enable) { /* Decrypt packet */
int oldaction = dtls->action; buffersize = capwap_decrypt_packet(&g_wtp.dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
/* Decrypt packet */ buffer = bufferplain;
buffersize = capwap_decrypt_packet(dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE); check = CAPWAP_PLAIN_PACKET;
if (buffersize > 0) { } else if (buffersize == CAPWAP_ERROR_AGAIN) {
buffer = bufferplain; /* Check is handshake complete */
check = CAPWAP_PLAIN_PACKET; if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (g_wtp.dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
} else if (buffersize == CAPWAP_ERROR_AGAIN) { if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
/* Check is handshake complete */ check = CAPWAP_NONE_PACKET;
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) { wtp_send_join();
if (socket.isctrlsocket) { } else {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) { check = CAPWAP_WRONG_PACKET;
check = CAPWAP_NONE_PACKET;
wtp_send_join();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
} else {
if (g_wtp.state == CAPWAP_DATA_CHECK_STATE) {
check = CAPWAP_NONE_PACKET;
wtp_start_datachannel();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
}
}
continue; /* Next packet */
} else {
if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
wtp_teardown_connection(); wtp_teardown_connection();
} }
continue; /* Next packet */
} }
continue; /* Next packet */
} else { } else {
continue; /* Drop packet */ if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (g_wtp.dtls.action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
wtp_teardown_connection();
}
continue; /* Next packet */
} }
} else if (check == CAPWAP_WRONG_PACKET) { } else if (check == CAPWAP_WRONG_PACKET) {
capwap_logging_debug("Warning: sanity check failure"); capwap_logging_debug("Warning: sanity check failure");
@ -450,30 +404,8 @@ int wtp_dfa_running(void) {
if (check == CAPWAP_PLAIN_PACKET) { if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_packet_rxmng* rxmngpacket; struct capwap_packet_rxmng* rxmngpacket;
/* Detect local address */
if (recvtoaddr.ss_family == AF_UNSPEC) {
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_wtp.net.bind_interface, (!(g_wtp.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(g_wtp.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo));
}
}
/* */
if (socket.isctrlsocket) {
capwap_logging_debug("Receive control packet");
} else {
capwap_logging_debug("Receive data packet");
}
/* Defragment management */ /* Defragment management */
rxmngpacket = wtp_get_packet_rxmng(socket.isctrlsocket); rxmngpacket = wtp_get_packet_rxmng();
/* If request, defragmentation packet */ /* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, buffersize); check = capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, buffersize);
@ -481,63 +413,61 @@ int wtp_dfa_running(void) {
continue; continue;
} else if (check != CAPWAP_RECEIVE_COMPLETE_PACKET) { } else if (check != CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Discard fragments */ /* Discard fragments */
wtp_free_packet_rxmng(socket.isctrlsocket); wtp_free_packet_rxmng();
continue; continue;
} }
/* Receive all fragment */
memcpy(&connection.socket, &socket, sizeof(struct capwap_socket));
memcpy(&connection.localaddr, &recvtoaddr, sizeof(struct sockaddr_storage));
memcpy(&connection.remoteaddr, &recvfromaddr, sizeof(struct sockaddr_storage));
/* Check for already response to packet */ /* Check for already response to packet */
if (socket.isctrlsocket) { if (capwap_is_request_type(rxmngpacket->ctrlmsg.type) && (g_wtp.remotetype == rxmngpacket->ctrlmsg.type) && (g_wtp.remoteseqnumber == rxmngpacket->ctrlmsg.seq)) {
if (capwap_recv_retrasmitted_request(&g_wtp.ctrldtls, rxmngpacket, &connection, g_wtp.lastrecvpackethash, g_wtp.responsefragmentpacket)) { /* Retransmit response */
wtp_free_packet_rxmng(socket.isctrlsocket); if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Retrasmitted packet"); capwap_logging_error("Error to resend response packet");
continue; } else {
capwap_logging_debug("Retrasmitted control packet");
} }
/* Check message type */ continue;
res = capwap_check_message_type(rxmngpacket); }
if (res != VALID_MESSAGE_TYPE) {
if (res == INVALID_REQUEST_MESSAGE_TYPE) {
capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
}
capwap_logging_debug("Invalid message type"); /* Check message type */
wtp_free_packet_rxmng(socket.isctrlsocket); res = capwap_check_message_type(rxmngpacket);
continue; if (res != VALID_MESSAGE_TYPE) {
if (res == INVALID_REQUEST_MESSAGE_TYPE) {
capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
} }
capwap_logging_debug("Invalid message type");
wtp_free_packet_rxmng();
continue;
} }
/* Parsing packet */ /* Parsing packet */
res = capwap_parsing_packet(rxmngpacket, &connection, &packet); res = capwap_parsing_packet(rxmngpacket, &packet);
if (res != PARSING_COMPLETE) { if (res != PARSING_COMPLETE) {
if (socket.isctrlsocket && (res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) { if ((res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
capwap_logging_warning("Unrecognized Message Element, send Response Packet with error"); capwap_logging_warning("Unrecognized Message Element, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT); wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT);
/* TODO: add the unrecognized message element */ /* TODO: add the unrecognized message element */
} }
/* */ /* */
capwap_free_parsed_packet(&packet); capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket); wtp_free_packet_rxmng();
capwap_logging_debug("Failed parsing packet"); capwap_logging_debug("Failed parsing packet");
continue; continue;
} }
/* Validate packet */ /* Validate packet */
if (capwap_validate_parsed_packet(&packet, NULL)) { if (capwap_validate_parsed_packet(&packet, NULL)) {
if (socket.isctrlsocket && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) { if (capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
capwap_logging_warning("Missing Mandatory Message Element, send Response Packet with error"); capwap_logging_warning("Missing Mandatory Message Element, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT); wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT);
} }
/* */ /* */
capwap_free_parsed_packet(&packet); capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket); wtp_free_packet_rxmng();
capwap_logging_debug("Failed validation parsed packet"); capwap_logging_debug("Failed validation parsed packet");
continue; continue;
} }
@ -547,7 +477,7 @@ int wtp_dfa_running(void) {
/* Free packet */ /* Free packet */
capwap_free_parsed_packet(&packet); capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket); wtp_free_packet_rxmng();
} }
} }
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == WTP_RECV_NOERROR_RADIO)) { } else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == WTP_RECV_NOERROR_RADIO)) {
@ -580,24 +510,32 @@ void wtp_free_reference_last_request(void) {
/* */ /* */
void wtp_free_reference_last_response(void) { void wtp_free_reference_last_response(void) {
capwap_list_flush(g_wtp.responsefragmentpacket); capwap_list_flush(g_wtp.responsefragmentpacket);
memset(&g_wtp.lastrecvpackethash[0], 0, sizeof(g_wtp.lastrecvpackethash)); g_wtp.remotetype = 0;
g_wtp.remoteseqnumber = 0;
} }
/* */ /* */
void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
g_wtp.retransmitcount++; if (!g_wtp.requestfragmentpacket->count) {
if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) { capwap_logging_warning("Invalid retransmition request packet");
/* Timeout state */
wtp_free_reference_last_request();
wtp_teardown_connection(); wtp_teardown_connection();
} else { } else {
/* Retransmit request */ g_wtp.retransmitcount++;
capwap_logging_debug("Retransmition request packet"); if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) {
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { capwap_logging_info("Retransmition request packet timeout");
capwap_logging_error("Error to send request packet");
}
/* Update timeout */ /* Timeout state */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL); wtp_free_reference_last_request();
wtp_teardown_connection();
} else {
/* Retransmit request */
capwap_logging_debug("Retransmition request packet");
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
capwap_logging_error("Error to send request packet");
}
/* Update timeout */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
}
} }
} }

View File

@ -13,14 +13,11 @@ struct wtp_discovery_response {
void wtp_free_discovery_response_array(void); void wtp_free_discovery_response_array(void);
/* */
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param);
/* */ /* */
void wtp_teardown_connection(void); void wtp_teardown_connection(void);
/* */ /* */
void wtp_free_packet_rxmng(int isctrlmsg); void wtp_free_packet_rxmng(void);
void wtp_free_reference_last_request(void); void wtp_free_reference_last_request(void);
void wtp_free_reference_last_response(void); void wtp_free_reference_last_response(void);
@ -69,6 +66,8 @@ void wtp_dfa_state_reset(void);
/* */ /* */
void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length); void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length);
int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype);
void wtp_recv_data_keepalive(void);
void wtp_recv_data(uint8_t* buffer, int length);
#endif /* __WTP_DFA_HEADER__ */ #endif /* __WTP_DFA_HEADER__ */

View File

@ -10,6 +10,7 @@
void wtp_send_configure(void) { void wtp_send_configure(void) {
int i; int i;
struct capwap_header_data capwapheader; struct capwap_header_data capwapheader;
struct capwap_acnamepriority_element acnamepriority;
struct capwap_packet_txmng* txmngpacket; struct capwap_packet_txmng* txmngpacket;
/* Build packet */ /* Build packet */
@ -21,8 +22,12 @@ void wtp_send_configure(void) {
wtp_create_radioadmstate_element(txmngpacket); wtp_create_radioadmstate_element(txmngpacket);
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_STATISTICSTIMER, &g_wtp.statisticstimer); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_STATISTICSTIMER, &g_wtp.statisticstimer);
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPREBOOTSTAT, &g_wtp.rebootstat); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPREBOOTSTAT, &g_wtp.rebootstat);
/* CAPWAP_ELEMENT_ACNAMEPRIORITY */ /* TODO */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_TRANSPORT, &g_wtp.transport); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_TRANSPORT, &g_wtp.transport);
acnamepriority.priority = 1;
acnamepriority.name = g_wtp.acname.name;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ACNAMEPRIORITY, &acnamepriority);
/* CAPWAP_ELEMENT_WTPSTATICIPADDRESS */ /* TODO */ /* CAPWAP_ELEMENT_WTPSTATICIPADDRESS */ /* TODO */
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
@ -86,7 +91,7 @@ void wtp_send_configure(void) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send Configuration Status request to AC */ /* Send Configuration Status request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE); wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -106,7 +111,7 @@ void wtp_dfa_state_configure(struct capwap_parsed_packet* packet) {
/* */ /* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CONFIGURATION_STATUS_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CONFIGURATION_STATUS_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */ /* Valid packet, free request packet */
wtp_free_reference_last_request(); wtp_free_reference_last_request();

View File

@ -32,7 +32,7 @@ void wtp_send_datacheck(void) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send Change State Event request to AC */ /* Send Change State Event request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE); wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -51,7 +51,7 @@ void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet) {
/* */ /* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CHANGE_STATE_EVENT_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CHANGE_STATE_EVENT_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */ /* Valid packet, free request packet */
wtp_free_reference_last_request(); wtp_free_reference_last_request();

View File

@ -28,76 +28,62 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
int i, j, w; int i, j, w;
int countwtp = -1; int countwtp = -1;
int indexpreferred = -1; int indexpreferred = -1;
union sockaddr_capwap checkaddr;
struct sockaddr_storage checkaddr; union sockaddr_capwap peeraddr;
struct sockaddr_in* checkaddripv4;
struct sockaddr_in6* checkaddripv6;
/* */ /* */
g_wtp.acctrladdress.ss_family = AF_UNSPEC; peeraddr.ss.ss_family = AF_UNSPEC;
/* Selected by preferred or less WTP by AC */ /* Selected by preferred or less WTP by AC */
for (i = 0; i < g_wtp.acdiscoveryresponse->count; i++) { for (i = 0; i < g_wtp.acdiscoveryresponse->count; i++) {
struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, i); struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, i);
/* AC with IPv4 */ /* AC with IPv4 */
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET)) { for (w = 0; w < response->controlipv4->count; w++) {
for (w = 0; w < response->controlipv4->count; w++) { struct capwap_controlipv4_element* controlipv4 = (struct capwap_controlipv4_element*)capwap_array_get_item_pointer(response->controlipv4, w);
struct capwap_controlipv4_element* controlipv4 = (struct capwap_controlipv4_element*)capwap_array_get_item_pointer(response->controlipv4, w);
/* Create IPv4 address */ /* Create IPv4 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage)); checkaddr.sin.sin_family = AF_INET;
checkaddripv4 = (struct sockaddr_in*)&checkaddr; memcpy(&checkaddr.sin.sin_addr, &controlipv4->address, sizeof(struct in_addr));
checkaddripv4->sin_family = AF_INET; checkaddr.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
checkaddripv4->sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv4->sin_addr, &controlipv4->address, sizeof(struct in_addr));
/* Check for preferred AC */ /* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) { for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j); union sockaddr_capwap* acpreferredaddr = (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) { if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j; indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage)); memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1)); break;
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
break;
}
} }
}
/* Check by number of WTP */ /* Check by number of WTP */
if (indexpreferred == -1) { if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) { if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
countwtp = controlipv4->wtpcount; countwtp = controlipv4->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage)); memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
}
} }
} }
} }
/* AC with IPv6 */ /* AC with IPv6 */
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET6)) { if ((g_wtp.net.localaddr.ss.ss_family == AF_INET6)) {
for (w = 0; w < response->controlipv6->count; w++) { for (w = 0; w < response->controlipv6->count; w++) {
struct capwap_controlipv6_element* controlipv6 = (struct capwap_controlipv6_element*)capwap_array_get_item_pointer(response->controlipv6, w); struct capwap_controlipv6_element* controlipv6 = (struct capwap_controlipv6_element*)capwap_array_get_item_pointer(response->controlipv6, w);
/* Create IPv6 address */ /* Create IPv6 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage)); checkaddr.sin6.sin6_family = AF_INET6;
checkaddripv6 = (struct sockaddr_in6*)&checkaddr; memcpy(&checkaddr.sin6.sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
checkaddripv6->sin6_family = AF_INET6; checkaddr.sin6.sin6_port = htons(CAPWAP_CONTROL_PORT);
checkaddripv6->sin6_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv6->sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
/* Check for preferred AC */ /* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) { for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j); union sockaddr_capwap* acpreferredaddr = (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) { if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j; indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage)); memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
break; break;
} }
} }
@ -106,9 +92,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
if (indexpreferred == -1) { if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv6->wtpcount)) { if ((countwtp == -1) || (countwtp > controlipv6->wtpcount)) {
countwtp = controlipv6->wtpcount; countwtp = controlipv6->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage)); memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
} }
} }
} }
@ -119,32 +103,24 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
wtp_free_discovery_response_array(); wtp_free_discovery_response_array();
/* Change state if found AC */ /* Change state if found AC */
if (g_wtp.acctrladdress.ss_family != AF_UNSPEC) { if (peeraddr.ss.ss_family != AF_UNSPEC) {
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage)); union sockaddr_capwap localaddr;
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
/* Retrieve local address */ /* Retrieve local address */
if (capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) { if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
struct sockaddr_storage sockinfo; CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); /* */
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) { capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */ /* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage)); if (!g_wtp.enabledtls) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1); wtp_send_join(); /* Bypass DTLS connection */
} else {
/* */ wtp_start_dtlssetup(); /* Create DTLS connection */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
} }
return;
} }
} }
} }
@ -193,15 +169,8 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
/* Send discovery request to AC */ /* Send discovery request to AC */
for (i = 0; i < g_wtp.acdiscoveryarray->count; i++) { for (i = 0; i < g_wtp.acdiscoveryarray->count; i++) {
int sock; if (!capwap_sendto_fragmentpacket(g_wtp.net.socket, g_wtp.requestfragmentpacket, (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i))) {
struct sockaddr_storage* sendtoaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i); capwap_logging_debug("Warning: error to send discovery request packet");
sock = capwap_get_socket(&g_wtp.net, sendtoaddr->ss_family, IPPROTO_UDP, 1);
if (sock >= 0) {
if (!capwap_sendto_fragmentpacket(sock, g_wtp.requestfragmentpacket, NULL, sendtoaddr)) {
capwap_logging_debug("Warning: error to send discovery request packet");
break;
}
} }
} }
@ -223,7 +192,7 @@ void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) {
/* */ /* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
struct capwap_resultcode_element* resultcode; struct capwap_resultcode_element* resultcode;
/* Check the success of the Request */ /* Check the success of the Request */

View File

@ -7,23 +7,14 @@ static void wtp_dfa_state_dtlsconnect_timeout(struct capwap_timeout* timeout, un
wtp_teardown_connection(); wtp_teardown_connection();
} }
/* DTLS BIO send */
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct capwap_socket* socket = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrlsock : &g_wtp.acdatasock);
struct sockaddr_storage* wtpaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.wtpctrladdress : &g_wtp.wtpdataaddress);
struct sockaddr_storage* acaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrladdress : &g_wtp.acdataaddress);
return capwap_sendto(socket->socket[socket->type], buffer, length, wtpaddress, acaddress);
}
/* */ /* */
void wtp_start_dtlssetup(void) { void wtp_start_dtlssetup(void) {
/* Create DTLS session */ /* Create DTLS session */
if (!capwap_crypt_createsession(&g_wtp.ctrldtls, CAPWAP_DTLS_CONTROL_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) { if (!capwap_crypt_createsession(&g_wtp.dtls, &g_wtp.dtlscontext)) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} else { } else {
if (capwap_crypt_open(&g_wtp.ctrldtls, &g_wtp.acctrladdress) == CAPWAP_HANDSHAKE_ERROR) { if (capwap_crypt_open(&g_wtp.dtls) == CAPWAP_HANDSHAKE_ERROR) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE); wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} else { } else {
@ -35,77 +26,34 @@ void wtp_start_dtlssetup(void) {
/* */ /* */
void wtp_start_datachannel(void) { void wtp_start_datachannel(void) {
struct capwap_list* txfragpacket; union sockaddr_capwap dataaddr;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
/* If need, create DTLS Data channel crypted */ /* Set AC data address */
if (g_wtp.dtlsdatapolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) { memcpy(&dataaddr, &g_wtp.dtls.peeraddr, sizeof(union sockaddr_capwap));
if (!g_wtp.datadtls.enable) { CAPWAP_SET_NETWORK_PORT(&dataaddr, (CAPWAP_GET_NETWORK_PORT(&g_wtp.dtls.peeraddr) + 1));
/* Create DTLS data session before send data keepalive */
if (capwap_crypt_createsession(&g_wtp.datadtls, CAPWAP_DTLS_DATA_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) {
if (capwap_crypt_open(&g_wtp.datadtls, &g_wtp.acdataaddress) == CAPWAP_HANDSHAKE_CONTINUE) {
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_DTLS_INTERVAL, wtp_dfa_state_dtlsconnect_timeout, NULL, NULL); /* Wait complete dtls handshake */
} else {
wtp_teardown_connection();
}
} else {
wtp_teardown_connection();
}
return; /* Connect to AC data channel */
} else if (g_wtp.datadtls.action != CAPWAP_DTLS_ACTION_DATA) { if (!wtp_kmod_connect(&dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu)) {
wtp_teardown_connection(); /* Reset AC Prefered List Position */
return; g_wtp.acpreferedselected = 0;
}
}
/* Build packet */ /* Set timer */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, g_wtp.binding); wtp_dfa_change_state(CAPWAP_RUN_STATE);
capwap_header_set_keepalive_flag(&capwapheader, 1); capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu); /* CAPWAP_DONT_FRAGMENT */ capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &g_wtp.sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0);
if (txfragpacket->count == 1) {
/* Send Data keepalive to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;
/* Set timer */
wtp_dfa_change_state(CAPWAP_RUN_STATE);
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} else {
/* Error to send packets */
capwap_logging_debug("Warning: error to send data channel keepalive packet");
wtp_teardown_connection();
}
} else { } else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet"); /* Error to send packets */
capwap_logging_error("Error to send data channel keepalive packet");
wtp_teardown_connection(); wtp_teardown_connection();
} }
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
} }
/* */ /* */
static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
/* Free and reset resource */ /* Free and reset resource */
if (g_wtp.ctrldtls.enable) { if (g_wtp.dtls.enable) {
capwap_crypt_freesession(&g_wtp.ctrldtls); capwap_crypt_freesession(&g_wtp.dtls);
}
if (g_wtp.datadtls.enable) {
capwap_crypt_freesession(&g_wtp.datadtls);
} }
/* */ /* */
@ -117,8 +65,7 @@ static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, u
/* */ /* */
wtp_free_reference_last_request(); wtp_free_reference_last_request();
wtp_free_reference_last_response(); wtp_free_reference_last_response();
wtp_free_packet_rxmng(0); wtp_free_packet_rxmng();
wtp_free_packet_rxmng(1);
/* */ /* */
if (!g_wtp.running) { if (!g_wtp.running) {
@ -140,15 +87,15 @@ void wtp_dfa_state_dtlsteardown(struct capwap_parsed_packet* packet) {
void wtp_teardown_connection(void) { void wtp_teardown_connection(void) {
g_wtp.teardown = 1; g_wtp.teardown = 1;
/* TODO: close SSID ? */
/* DTSL Control */ /* DTSL Control */
if (g_wtp.ctrldtls.enable) { if (g_wtp.dtls.enable) {
capwap_crypt_close(&g_wtp.ctrldtls); capwap_crypt_close(&g_wtp.dtls);
} }
/* DTLS Data */ /* Close data channel session */
if (g_wtp.datadtls.enable) { wtp_kmod_resetsession();
capwap_crypt_close(&g_wtp.datadtls);
}
/* */ /* */
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE); wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE);

View File

@ -13,40 +13,30 @@ void wtp_dfa_state_idle(void) {
/* */ /* */
if (!g_wtp.acdiscoveryrequest && (g_wtp.acpreferedarray->count > 0)) { if (!g_wtp.acdiscoveryrequest && (g_wtp.acpreferedarray->count > 0)) {
while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) { while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) {
union sockaddr_capwap localaddr;
union sockaddr_capwap peeraddr;
/* Found in configuration file the AC address */ /* Found in configuration file the AC address */
memcpy(&g_wtp.acctrladdress, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(struct sockaddr_storage)); memcpy(&peeraddr, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(union sockaddr_capwap));
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
/* Next AC */ /* Next AC */
g_wtp.acpreferedselected++; g_wtp.acpreferedselected++;
/* Configure socket */
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, CAPWAP_CTRL_SOCKET));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acdataaddress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
/* Retrieve local address */ /* Retrieve local address */
if (capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) { if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
struct sockaddr_storage sockinfo; CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); /* */
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) { capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */ /* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage)); if (!g_wtp.enabledtls) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1); wtp_send_join(); /* Bypass DTLS connection */
} else {
/* */ wtp_start_dtlssetup(); /* Create DTLS connection */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
} }
return;
} }
} }
} }

View File

@ -48,15 +48,15 @@ void wtp_send_join(void) {
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ECNSUPPORT, &g_wtp.ecn); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ECNSUPPORT, &g_wtp.ecn);
if (g_wtp.wtpctrladdress.ss_family == AF_INET) { if (g_wtp.dtls.localaddr.ss.ss_family == AF_INET) {
struct capwap_localipv4_element addr; struct capwap_localipv4_element addr;
memcpy(&addr.address, &((struct sockaddr_in*)&g_wtp.wtpctrladdress)->sin_addr, sizeof(struct in_addr)); memcpy(&addr.address, &g_wtp.dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr);
} else if (g_wtp.wtpctrladdress.ss_family == AF_INET6) { } else if (g_wtp.dtls.localaddr.ss.ss_family == AF_INET6) {
struct capwap_localipv6_element addr; struct capwap_localipv6_element addr;
memcpy(&addr.address, &((struct sockaddr_in6*)&g_wtp.wtpctrladdress)->sin6_addr, sizeof(struct in6_addr)); memcpy(&addr.address, &g_wtp.dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr); capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr);
} }
@ -76,7 +76,7 @@ void wtp_send_join(void) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send join request to AC */ /* Send join request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_JOIN_STATE); wtp_dfa_change_state(CAPWAP_JOIN_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -97,7 +97,7 @@ void wtp_dfa_state_join(struct capwap_parsed_packet* packet) {
/* */ /* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header); binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_JOIN_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_JOIN_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */ /* Valid packet, free request packet */
wtp_free_reference_last_request(); wtp_free_reference_last_request();

View File

@ -5,10 +5,6 @@
#include "wtp_radio.h" #include "wtp_radio.h"
#include "ieee80211.h" #include "ieee80211.h"
/* */
#define WTP_BODY_PACKET_MAX_SIZE 8192
static uint8_t g_bodypacket[WTP_BODY_PACKET_MAX_SIZE];
/* */ /* */
static int send_echo_request(void) { static int send_echo_request(void) {
int result = -1; int result = -1;
@ -33,7 +29,7 @@ static int send_echo_request(void) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Send echo request to AC */ /* Send echo request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
result = 0; result = 0;
} else { } else {
/* Error to send packets */ /* Error to send packets */
@ -94,11 +90,11 @@ static void receive_reset_request(struct capwap_parsed_packet* packet) {
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send Reset response to AC */ /* Send Reset response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send reset response packet"); capwap_logging_debug("Warning: error to send reset response packet");
} }
} }
@ -143,11 +139,11 @@ static void receive_station_configuration_request(struct capwap_parsed_packet* p
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send Station Configuration response to AC */ /* Send Station Configuration response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send Station Configuration response packet"); capwap_logging_debug("Warning: error to send Station Configuration response packet");
} }
} }
@ -203,213 +199,133 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
capwap_packet_txmng_free(txmngpacket); capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */ /* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq; g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send IEEE802.11 WLAN Configuration response to AC */ /* Send IEEE802.11 WLAN Configuration response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) { if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send IEEE802.11 WLAN Configuration response packet"); capwap_logging_debug("Warning: error to send IEEE802.11 WLAN Configuration response packet");
} }
} }
} }
/* */
static void send_data_keepalive_request() {
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, g_wtp.binding);
capwap_header_set_keepalive_flag(&capwapheader, 1);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu); /* CAPWAP_DONT_FRAGMENT */
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &g_wtp.sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0);
if (txfragpacket->count == 1) {
/* Send Data keepalive to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalive);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} else {
/* Error to send packets */
capwap_logging_debug("Warning: error to send data channel keepalive packet");
wtp_teardown_connection();
}
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet");
wtp_teardown_connection();
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
}
/* */
int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype) {
int result;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
ASSERT(IS_VALID_RADIOID(radioid));
ASSERT(IS_VALID_WLANID(wlanid));
ASSERT(frame != NULL);
ASSERT(length > 0);
/* Check for IEEE 802.3 frame */
if (!nativeframe && (!bssaddress || (bssaddresstype == MACADDRESS_NONE_LENGTH))) {
return 0;
}
/* Build packet */
capwap_header_init(&capwapheader, radioid, g_wtp.binding);
capwap_header_set_nativeframe_flag(&capwapheader, (nativeframe ? 1: 0));
/* Set radio macaddress */
if (!nativeframe) {
capwap_header_set_radio_macaddress(&capwapheader, bssaddresstype, bssaddress);
}
/* Set wireless information */
if (rssi || snr || rate) {
struct capwap_ieee80211_frame_info frameinfo;
frameinfo.rssi = rssi;
frameinfo.snr = snr;
frameinfo.rate = htons(rate);
capwap_header_set_wireless_information(&capwapheader, &frameinfo, sizeof(struct capwap_ieee80211_frame_info));
}
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu);
/* */
capwap_packet_txmng_add_data(txmngpacket, frame, (unsigned short)length);
/* Data message complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, g_wtp.fragmentid);
if (txfragpacket->count > 1) {
g_wtp.fragmentid++;
}
/* */
result = capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress);
if (!result) {
capwap_logging_debug("Warning: error to send data packet");
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}
/* */ /* */
void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_debug("Send Echo Request");
if (!send_echo_request()) { if (!send_echo_request()) {
g_wtp.retransmitcount = 0; g_wtp.retransmitcount = 0;
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL); capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
} else { } else {
capwap_logging_error("Unable to send Echo Request");
wtp_teardown_connection(); wtp_teardown_connection();
} }
} }
/* */ /* */
void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
send_data_keepalive_request(); capwap_logging_debug("Send Keep-Alive");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalive);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
if (wtp_kmod_send_keepalive()) {
capwap_logging_error("Unable to send Keep-Alive");
wtp_teardown_connection();
}
} }
/* */ /* */
void wtp_dfa_state_run_keepalivedead_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { void wtp_dfa_state_run_keepalivedead_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_info("Keep-Alive timeout, teardown");
wtp_teardown_connection(); wtp_teardown_connection();
} }
/* */
void wtp_recv_data_keepalive(void) {
capwap_logging_debug("Receive Keep-Alive");
/* Receive Data Keep-Alive, wait for next packet */
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalivedead);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalive, WTP_DATACHANNEL_KEEPALIVE_INTERVAL, wtp_dfa_state_run_keepalive_timeout, NULL, NULL);
}
/* */
void wtp_recv_data(uint8_t* buffer, int length) {
int headersize;
struct capwap_header* header = (struct capwap_header*)buffer;
/* */
if (length < sizeof(struct capwap_header)) {
return;
}
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if ((length - headersize) > 0) {
wtp_radio_receive_data_packet(GET_RID_HEADER(header), GET_WBID_HEADER(header), (buffer + headersize), (length - headersize));
}
}
/* */ /* */
void wtp_dfa_state_run(struct capwap_parsed_packet* packet) { void wtp_dfa_state_run(struct capwap_parsed_packet* packet) {
ASSERT(packet != NULL); ASSERT(packet != NULL);
if (packet->rxmngpacket->isctrlpacket) { if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) { switch (packet->rxmngpacket->ctrlmsg.type) {
switch (packet->rxmngpacket->ctrlmsg.type) { case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: { /* TODO */
/* TODO */ break;
break;
}
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_ECHO_RESPONSE: {
if (!receive_echo_response(packet)) {
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
/* TODO */
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
receive_station_configuration_request(packet);
break;
}
case CAPWAP_RESET_REQUEST: {
receive_reset_request(packet);
wtp_dfa_change_state(CAPWAP_RESET_STATE);
wtp_dfa_state_reset();
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
receive_ieee80211_wlan_configuration_request(packet);
break;
}
} }
}
} else {
if (IS_FLAG_K_HEADER(packet->rxmngpacket->header)) {
if (!memcmp(capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID), &g_wtp.sessionid, sizeof(struct capwap_sessionid_element))) {
/* Receive Data Keep-Alive, wait for next packet */
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalivedead);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalive, WTP_DATACHANNEL_KEEPALIVE_INTERVAL, wtp_dfa_state_run_keepalive_timeout, NULL, NULL);
}
} else {
/* Get body packet */
int bodypacketlength = capwap_packet_getdata(packet->rxmngpacket, g_bodypacket, WTP_BODY_PACKET_MAX_SIZE);
if (bodypacketlength > 0) {
uint8_t radioid = GET_RID_HEADER(packet->rxmngpacket->header);
unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header);
wtp_radio_receive_data_packet(radioid, binding, g_bodypacket, bodypacketlength); case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_ECHO_RESPONSE: {
if (!receive_echo_response(packet)) {
capwap_logging_debug("Receive Echo Response");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
/* TODO */
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
receive_station_configuration_request(packet);
break;
}
case CAPWAP_RESET_REQUEST: {
receive_reset_request(packet);
wtp_dfa_change_state(CAPWAP_RESET_STATE);
wtp_dfa_state_reset();
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
receive_ieee80211_wlan_configuration_request(packet);
break;
} }
} }
} }

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