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
Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
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.
Please see the relevant section below for information on each type of license.
Open Source:
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.
Commercial Licensing:
Businesses and enterprises who wish to incorporate SmartCAPWAP products into proprietary appliances or
other commercial software products for re-distribution must license commercial versions.
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.
SmartCAPWAP -- An Open Source CAPWAP WTP / AC
Copyright (C) 2012-2013 Massimo Vellucci <vemax78@gmail.com>
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.
Please see the relevant section below for information on each type of license.
Open Source:
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.
Commercial Licensing:
Businesses and enterprises who wish to incorporate SmartCAPWAP products into proprietary appliances or
other commercial software products for re-distribution must license commercial versions.
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,7 +40,7 @@ define KernelPackage/smartcapwap
SUBMENU:=Network Support
TITLE:=SmartCAPWAP Data Channel Module
MAINTAINER:=Massimo Vellucci <vemax78@gmail.com>
DEPENDS:=+kmod-mac80211
DEPENDS:=+kmod-mac80211 +kmod-ipv6
FILES:=$(PKG_BUILD_DIR)/src/wtp/kmod/smartcapwap.ko
AUTOLOAD:=$(call AutoLoad,70,smartcapwap)
endef
@ -74,7 +74,7 @@ define Build/Compile/kmod
SUBDIRS="$(PKG_BUILD_DIR)/src/wtp/kmod" \
KLIB_BUILD="$(LINUX_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 \
-I$(STAGING_DIR)/usr/include/mac80211-backport \
-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
+++ b/include/net/mac80211.h 2014-06-07 17:23:03.000000000 +0200
@@ -4699,4 +4699,24 @@ int ieee80211_parse_p2p_noa(const struct
--- a/include/net/mac80211.h 2014-07-10 19:19:55.000000000 +0200
+++ b/include/net/mac80211.h 2014-07-10 20:52:02.000000000 +0200
@@ -4772,4 +4772,24 @@ int ieee80211_parse_p2p_noa(const struct
*/
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 */
--- a/net/mac80211/ieee80211_i.h 2014-06-02 11:48:37.000000000 +0200
+++ b/net/mac80211/ieee80211_i.h 2014-06-07 17:14:25.000000000 +0200
--- a/net/mac80211/ieee80211_i.h 2014-07-10 19:19:55.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
#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u)
#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u)
@ -35,7 +35,7 @@
/**
* 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];
@ -45,34 +45,17 @@
/* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
--- a/net/mac80211/iface.c 2014-06-02 11:48:37.000000000 +0200
+++ b/net/mac80211/iface.c 2014-06-04 22:52:06.000000000 +0200
@@ -1850,3 +1850,80 @@ void ieee80211_iface_exit(void)
--- a/net/mac80211/iface.c 2014-07-10 19:19:55.000000000 +0200
+++ b/net/mac80211/iface.c 2014-07-10 20:51:28.000000000 +0200
@@ -1844,3 +1844,45 @@ void ieee80211_iface_exit(void)
{
unregister_netdevice_notifier(&mac80211_netdev_notifier);
}
+
+
+int ieee80211_pcktunnel_register(u32 ifindex, struct ieee80211_pcktunnel *handler)
+int ieee80211_pcktunnel_register(struct net_device *dev, struct ieee80211_pcktunnel *handler)
+{
+ int ret = 0;
+ struct net_device *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);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ mutex_lock(&sdata->local->iflist_mtx);
+
@ -85,33 +68,16 @@
+ mutex_unlock(&sdata->local->iflist_mtx);
+ synchronize_net();
+
+ dev_put(dev);
+ return ret;
+}
+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;
+ struct net_device *dev;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ 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);
+
+ h = rcu_dereference_protected(sdata->pcktunnel_handlers, lockdep_is_held(&sdata->local->iflist_mtx));
@ -123,14 +89,13 @@
+ mutex_unlock(&sdata->local->iflist_mtx);
+ synchronize_net();
+
+ dev_put(dev);
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_pcktunnel_deregister);
+
--- a/net/mac80211/rx.c 2014-06-02 11:48:37.000000000 +0200
+++ b/net/mac80211/rx.c 2014-06-07 17:22:05.000000000 +0200
@@ -2828,6 +2828,51 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
--- a/net/mac80211/rx.c 2014-07-10 19:19:55.000000000 +0200
+++ b/net/mac80211/rx.c 2014-07-10 21:01:19.000000000 +0200
@@ -2831,6 +2831,51 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
return RX_QUEUED;
}
@ -182,7 +147,7 @@
/* TODO: use IEEE80211_RX_FRAGMENTED */
static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
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)
rx->sta->rx_dropped++;
/* fall through */
@ -190,17 +155,18 @@
case RX_CONTINUE: {
struct ieee80211_rate *rate = NULL;
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,
- struct sk_buff_head *frames)
+ struct sk_buff_head *frames,
+ struct ieee80211_rate *rate)
+
{
ieee80211_rx_result res = RX_DROP_MONITOR;
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))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
@ -212,7 +178,7 @@
CALL_RXH(ieee80211_rx_h_amsdu)
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);
}
@ -222,7 +188,7 @@
{
struct sk_buff_head reorder_release;
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);
@ -231,7 +197,7 @@
return;
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);
spin_unlock(&tid_agg_rx->reorder_lock);
@ -240,7 +206,7 @@
}
/* 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.
*/
static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
@ -251,7 +217,7 @@
{
struct ieee80211_local *local = rx->local;
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;
}
@ -260,7 +226,7 @@
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.
*/
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
@ -270,7 +236,7 @@
{
struct ieee80211_local *local = hw_to_local(hw);
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.sdata = prev_sta->sdata;
@ -279,7 +245,7 @@
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.sdata = prev_sta->sdata;
@ -288,7 +254,7 @@
return;
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.sdata = prev;
@ -297,7 +263,7 @@
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.sdata = prev;
@ -306,7 +272,7 @@
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,
((struct ieee80211_hdr *)skb->data)->frame_control,
skb->len);

View File

@ -37,9 +37,13 @@ static int ac_init(void) {
/* Network */
capwap_network_init(&g_ac.net);
g_ac.addrlist = capwap_list_create();
g_ac.mtu = CAPWAP_MTU_DEFAULT;
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 */
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_list_free(g_ac.addrlist);
}
/* Help */
@ -144,8 +149,6 @@ static void ac_print_usage(void) {
static int ac_parsing_configuration_1_0(config_t* config) {
int i;
int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
config_setting_t* configSetting;
@ -519,7 +522,7 @@ static int ac_parsing_configuration_1_0(config_t* config) {
return 0;
}
strcpy(g_ac.net.bind_interface, configString);
strcpy(g_ac.net.bindiface, configString);
}
/* 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 */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
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 */
if (config_lookup_string(config, "backend.id", &configString) == CONFIG_TRUE) {
if (strlen(configString) > 0) {
@ -754,12 +718,15 @@ static int ac_load_configuration(int argc, char** argv) {
/* Init AC */
static int ac_configure(void) {
/* Bind to any address */
if (!capwap_bind_sockets(&g_ac.net)) {
/* Bind control channel to any address */
if (capwap_bind_sockets(&g_ac.net)) {
capwap_logging_fatal("Cannot bind address");
return AC_ERROR_NETWORK;
}
/* Detect local address */
capwap_interface_list(&g_ac.net, g_ac.addrlist);
return CAPWAP_SUCCESSFUL;
}
@ -834,24 +801,27 @@ int main(int argc, char** argv) {
result = ac_configure();
if (result == CAPWAP_SUCCESSFUL) {
/* Connect AC to kernel module */
value = ac_kmod_init();
if (!value || !g_ac.kmodrequest) {
if (ac_kmod_isconnected()) {
if (!ac_kmod_init(16, 4)) {
/* Bind data channel */
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");
/* 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 */
ac_kmod_free();
} else {
capwap_logging_fatal("Unable to connect to kernel module");
}
/* Close connection */
ac_close();
}
}
/* Free memory */

View File

@ -61,6 +61,13 @@
#define AC_STATIONS_HASH_SIZE 65536
#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 capwap_ecnsupport_element ecn;
@ -98,10 +105,9 @@ struct ac_t {
/* */
struct ac_state dfa;
struct capwap_network net;
struct capwap_list* addrlist;
unsigned short mtu;
struct ac_fds fds;
struct capwap_array* binding;
struct capwap_acname_element acname;
@ -111,7 +117,6 @@ struct ac_t {
int fdmsgsessions[2];
/* */
int kmodrequest;
struct ac_kmod_handle kmodhandle;
/* 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);
/* 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)) {
int radioid = json_object_get_int(jsonitem);
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;
/* */
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)) {
antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE);
} else {
@ -29,7 +29,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
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)) {
antenna->combiner = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -37,7 +37,7 @@ static void* ac_json_80211_antenna_createmessageelement(struct json_object* json
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)) {
int i;
int length;

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
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)) {
directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
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)) {
directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_directsequencecontrol_createmessageelement(struct jso
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)) {
directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -30,7 +30,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -38,7 +38,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->longretry = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -46,7 +46,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -54,7 +54,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else {
@ -62,7 +62,7 @@ static void* ac_json_80211_macoperation_createmessageelement(struct json_object*
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)) {
macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
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)) {
multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
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)) {
multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_multidomaincapability_createmessageelement(struct jso
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)) {
multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem);
} else {

View File

@ -19,7 +19,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
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)) {
ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -27,7 +27,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
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)) {
ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK;
} else {
@ -35,7 +35,7 @@ static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object*
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)) {
ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem);
} else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_txpower_createmessageelement(struct json_object* json
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)) {
txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem);
} else {

View File

@ -22,7 +22,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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)) {
wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -30,7 +30,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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)) {
wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -38,7 +38,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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)) {
wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem);
} else {
@ -46,7 +46,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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 (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) {
capwap_free(wtpradioconf);
@ -57,7 +57,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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)) {
wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem);
} else {
@ -65,7 +65,7 @@ static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object*
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)) {
const char* country = json_object_get_string(jsonitem);
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;
/* */
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)) {
wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem);
} 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)) {
wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem);
} else {

View File

@ -17,7 +17,7 @@ static void* ac_json_80211_wtpradioinformation_createmessageelement(struct json_
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)) {
wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK;
} else {

View File

@ -45,7 +45,7 @@ static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct
*/
/* 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)) {
return 0;
}
@ -93,19 +93,19 @@ static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_ob
*/
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
jsonvendor = json_object_object_get(jsonimage, "Vendor");
jsondata = json_object_object_get(jsonimage, "Data");
jsonvendor = compat_json_object_object_get(jsonimage, "Vendor");
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)) {
return 0;
}
@ -186,25 +186,25 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
*/
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
@ -213,37 +213,37 @@ static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_obj
/* TODO */
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
return 0;
}
/* 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)) {
ssid = json_object_get_string(jsonssid);
if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) {
@ -386,16 +386,16 @@ static void ac_backend_parsing_event(struct json_object* jsonitem) {
*/
/* 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)) {
const char* idevent = json_object_get_string(jsonvalue);
/* 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)) {
const char* action = json_object_get_string(jsonvalue);
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)) {
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 */
memcpy(&responsetimers, &session->dfa.timers, sizeof(struct capwap_timers_element));
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)) {
struct json_object* jsonitem;
/* 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)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) {
@ -438,7 +438,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
}
/* 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)) {
int value = json_object_get_int(jsonitem);
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 */
jsonelement = NULL;
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)) {
length = json_object_array_length(jsonelement);
} else {
@ -480,12 +480,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* 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)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256) && ((uint8_t)value == report.radioid)) {
/* 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)) {
value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 65536)) {
@ -506,12 +506,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* IdleTimeout */
memcpy(&responseidletimeout, &session->dfa.idletimeout, sizeof(struct capwap_idletimeout_element));
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)) {
struct json_object* jsonitem;
/* 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)) {
int value = json_object_get_int(jsonitem);
if (value > 0) {
@ -526,12 +526,12 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* WTPFallback */
memcpy(&responsewtpfallback, &session->dfa.wtpfallback, sizeof(struct capwap_wtpfallback_element));
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)) {
struct json_object* jsonitem;
/* 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)) {
int value = json_object_get_int(jsonitem);
if ((value > 0) && (value < 256)) {
@ -546,7 +546,7 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
/* ACIPv4List */
jsonelement = NULL;
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)) {
length = json_object_array_length(jsonelement);
} else {
@ -567,17 +567,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* 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)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */
if (address.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
if (address.ss.ss_family == AF_INET) {
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 */
jsonelement = NULL;
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)) {
length = json_object_array_length(jsonelement);
} else {
@ -619,17 +618,16 @@ static uint32_t ac_dfa_state_configure_create_response(struct ac_session_t* sess
struct json_object* jsonitem;
/* 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)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */
if (address.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
if (address.ss.ss_family == AF_INET6) {
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 */
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)) {
struct json_object* jsonitem;
/* 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)) {
struct sockaddr_storage address;
union sockaddr_capwap address;
const char* addressvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(addressvalue, &address)) {
if (address.ss_family == AF_INET) {
if (address.ss.ss_family == AF_INET) {
/* 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)) {
struct sockaddr_storage netmask;
union sockaddr_capwap netmask;
const char* netmaskvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(netmaskvalue, &netmask)) {
if (netmask.ss_family == AF_INET) {
if (netmask.ss.ss_family == AF_INET) {
/* 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)) {
struct sockaddr_storage gateway;
union sockaddr_capwap gateway;
const char* gatewayvalue = json_object_get_string(jsonitem);
if (capwap_address_from_string(gatewayvalue, &gateway)) {
if (gateway.ss_family == AF_INET) {
if (gateway.ss.ss_family == AF_INET) {
/* 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)) {
int value = json_object_get_int(jsonitem);
struct capwap_wtpstaticipaddress_element responsewtpstaticipaddress;
memcpy(&responsewtpstaticipaddress.address, &((struct sockaddr_in*)&address)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.netmask, &((struct sockaddr_in*)&netmask)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.gateway, &((struct sockaddr_in*)&gateway)->sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.address, &address.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.netmask, &netmask.sin.sin_addr, sizeof(struct in_addr));
memcpy(&responsewtpstaticipaddress.gateway, &gateway.sin.sin_addr, sizeof(struct in_addr));
responsewtpstaticipaddress.staticip = (uint8_t)value;
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);
/* 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 (ac_json_ieee80211_parsingjson(&wtpradio, jsonelement)) {
/* 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);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* 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 */
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 */
if (CAPWAP_RESULTCODE_OK(result)) {
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 {
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;
}
/* */
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) {
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) {
result = ac_dfa_state_datacheck_create_response(session, packet, response, txmngpacket);
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 */
@ -220,11 +222,11 @@ void ac_dfa_state_datacheck(struct ac_session_t* session, struct capwap_parsed_p
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* 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 */
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 */
if (CAPWAP_RESULTCODE_OK(result)) {
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 {
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 "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) {
ASSERT(session != NULL);
/* 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;
}
if (capwap_crypt_open(&session->dtls, &session->connection.remoteaddr) == CAPWAP_HANDSHAKE_ERROR) {
if (capwap_crypt_open(&session->dtls) == CAPWAP_HANDSHAKE_ERROR) {
return 0;
}
/* Wait DTLS handshake complete */
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);
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;
}
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_DTLS_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
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);
/* */
jsonelement = json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
jsonelement = compat_json_object_object_get(jsonroot, IEEE80211_BINDING_JSON_ROOT);
if (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) {
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;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
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;
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 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;
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);
} else if (session->connection.localaddr.ss_family == AF_INET6) {
} else if (session->dtls.localaddr.ss.ss_family == AF_INET6) {
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);
}
/* ACIPv4List */
jsonelement = NULL;
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)) {
length = json_object_array_length(jsonelement);
} else {
@ -484,17 +484,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem;
/* 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)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv4 address */
if (address.ss_family == AF_INET) {
struct sockaddr_in* address_in = (struct sockaddr_in*)&address;
if (address.ss.ss_family == AF_INET) {
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 */
jsonelement = NULL;
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)) {
length = json_object_array_length(jsonelement);
} else {
@ -536,17 +535,16 @@ static uint32_t ac_dfa_state_join_create_response(struct ac_session_t* session,
struct json_object* jsonitem;
/* 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)) {
const char* value = json_object_get_string(jsonitem);
if (value) {
struct sockaddr_storage address;
union sockaddr_capwap address;
if (capwap_address_from_string(value, &address)) {
/* Accept only IPv6 address */
if (address.ss_family == AF_INET6) {
struct sockaddr_in6* address_in6 = (struct sockaddr_in6*)&address;
if (address.ss.ss_family == AF_INET6) {
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;
}
/* */
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) {
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;
}
} else {
capwap_logging_info("WTP Id %s already used in another session", wtpid);
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;
memcpy(&session->sessionid, sessionid, sizeof(struct capwap_sessionid_element));
session->binding = binding;
} else {
} else if (wtpid) {
capwap_free(wtpid);
}
} 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;
}
} else {
@ -668,14 +667,14 @@ void ac_dfa_state_join(struct ac_session_t* session, struct capwap_parsed_packet
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
session->remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, session->lastrecvpackethash);
/* 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)) {
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 {
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);
/* Save remote sequence number */
session->remotetype = packet->rxmngpacket->ctrlmsg.type;
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 */
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 */
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);
/* 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)) {
rxmngrequestpacket = capwap_packet_rxmng_create_from_requestfragmentpacket(session->requestfragmentpacket);
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 */
if (capwap_get_message_element(&requestpacket, CAPWAP_ELEMENT_80211_ADD_WLAN)) {
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) {
struct ac_wlan* wlan;
struct ac_station* station;
struct capwap_addstation_element* addstation;
struct ac_notify_add_station_status notify;
struct capwap_80211_station_element* station80211;
unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header);
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);
/* */
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);
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;
memcpy(notify.address, addstation->address, MACADDRESS_EUI48_LENGTH);
notify.statuscode = resultcode->code;
ac_session_data_send_action(session->sessiondata, AC_SESSION_DATA_ACTION_ADD_STATION_STATUS, 0, (void*)&notify, sizeof(struct ac_notify_add_station_status));
/* */
station->flags |= AC_STATION_FLAGS_AUTHORIZED;
capwap_timeout_deletetimer(session->timeout, station->idtimeout);
station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET;
} else {
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) {
struct capwap_deletestation_element* deletestation;
struct ac_notify_delete_station_status notify;
struct ac_station* station;
struct capwap_resultcode_element* resultcode;
struct capwap_deletestation_element* deletestation;
/* */
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);
/* */
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);
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));
/* */
ac_stations_delete_station(session, station);
}
}
/* */
@ -187,7 +203,7 @@ static void receive_ieee80211_station_configuration_response(struct ac_session_t
/* Parsing request message */
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)) {
execute_ieee80211_station_configuration_response_addstation(session, packet, &requestpacket);
} 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: {
#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)) {
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_MAX_ECHO_INTERVAL, ac_dfa_teardown_timeout, session, NULL);
} else {

View File

@ -19,32 +19,32 @@ struct ac_discovery_t {
struct ac_discovery_packet {
int sendsock;
struct sockaddr_storage sender;
union sockaddr_capwap sender;
char data[0];
};
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 ac_discovery_packet* packet;
ASSERT(buffer != NULL);
ASSERT(buffersize > 0);
ASSERT(sock >= 0);
ASSERT(sender != NULL);
/* TODO: mettere un history delle discovery request già processate per non eseguirle di nuovo */
/* L'elemento deve rimanere per la durata minima di una discovery request */
/* Copy packet */
item = capwap_itemlist_create(sizeof(struct ac_discovery_packet) + buffersize);
packet = (struct ac_discovery_packet*)item->item;
packet->sendsock = sock;
memcpy(&packet->sender, sender, sizeof(struct sockaddr_storage));
memcpy(&packet->sender, sender, sizeof(union sockaddr_capwap));
memcpy(packet->data, buffer, buffersize);
/* Append to packets list */
capwap_lock_enter(&g_ac_discovery.packetslock);
capwap_itemlist_insert_after(g_ac_discovery.packets, NULL, item);
@ -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) {
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;
memcpy(&element.address, &((struct sockaddr_in*)&sessioncontrol->localaddress)->sin_addr, sizeof(struct in_addr));
element.wtpcount = sessioncontrol->count;
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;
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);
/* 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) {
/* Validate message */
if (capwap_check_message_type(rxmngpacket) == VALID_MESSAGE_TYPE) {
/* Parsing packet */
if (capwap_parsing_packet(rxmngpacket, NULL, &packet) == PARSING_COMPLETE) {
if (capwap_parsing_packet(rxmngpacket, &packet) == PARSING_COMPLETE) {
/* Validate packet */
if (!capwap_validate_parsed_packet(&packet, NULL)) {
struct capwap_packet_txmng* txmngpacket;
@ -185,7 +185,7 @@ static void ac_discovery_run(void) {
capwap_packet_txmng_free(txmngpacket);
/* 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");
}

View File

@ -3,6 +3,6 @@
int ac_discovery_start(void);
void ac_discovery_stop(void);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, struct sockaddr_storage* sender);
void ac_discovery_add_packet(void* buffer, int buffersize, int sock, union sockaddr_capwap* sender);
#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;
ASSERT(fds);
@ -113,8 +113,7 @@ static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct socka
ASSERT(buffer != NULL);
ASSERT(size != NULL);
ASSERT(*size > 0);
ASSERT(recvfromaddr != NULL);
ASSERT(recvtoaddr != NULL);
ASSERT(fromaddr != NULL);
/* Wait packet */
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 */
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;
}
@ -175,28 +174,6 @@ static void ac_session_add_packet(struct ac_session_t* session, char* buffer, in
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 */
void ac_session_send_action(struct ac_session_t* session, long action, long param, const void* data, long length) {
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);
}
/* 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 */
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 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;
ASSERT(session != NULL);
if (!capwap_compare_ip(address, &session->connection.remoteaddr)) {
if (!capwap_compare_ip(address, &session->dtls.peeraddr)) {
/* Increment session count */
capwap_lock_enter(&session->sessionlock);
session->count++;
@ -317,40 +250,6 @@ static struct ac_session_t* ac_search_session_from_wtpaddress(struct sockaddr_st
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 */
struct ac_session_t* ac_search_session_from_wtpid(const char* wtpid) {
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;
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 */
capwap_lock_enter(&session->sessionlock);
session->count++;
@ -468,14 +401,6 @@ void ac_session_close(struct ac_session_t* session) {
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 */
static void ac_close_sessions() {
struct capwap_list_item* search;
@ -493,45 +418,18 @@ static void ac_close_sessions() {
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);
}
/* 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 */
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;
struct capwap_list_item* itemlist;
struct ac_session_t* session;
ASSERT(acaddress != NULL);
ASSERT(wtpaddress != NULL);
ASSERT(sock != NULL);
ASSERT(sock >= 0);
ASSERT(fromaddr != NULL);
ASSERT(toaddr != NULL);
/* Create new session */
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->running = 1;
memcpy(&session->connection.socket, sock, sizeof(struct capwap_socket));
memcpy(&session->connection.localaddr, acaddress, sizeof(struct sockaddr_storage));
memcpy(&session->connection.remoteaddr, wtpaddress, sizeof(struct sockaddr_storage));
/* */
capwap_crypt_setconnection(&session->dtls, sock, toaddr, fromaddr);
/* */
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->idtimercontrol = capwap_timeout_createtimer(session->timeout);
session->idtimerkeepalivedead = capwap_timeout_createtimer(session->timeout);
/* Duplicate state for DFA */
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*/
if ((session->dfa.acipv4list.addresses->count == 0) && (session->dfa.acipv6list.addresses->count == 0)) {
if (acaddress->ss_family == AF_INET) {
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) {
struct in6_addr* acip = (struct in6_addr*)capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0);
memcpy(acip, &((struct sockaddr_in6*)acaddress)->sin6_addr, sizeof(struct in6_addr));
}
session->dfa.acipv4list.addresses = capwap_array_clone(g_ac.dfa.acipv4list.addresses);
if (!session->dfa.acipv4list.addresses->count && (session->dtls.localaddr.ss.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));
}
session->dfa.acipv6list.addresses = capwap_array_clone(g_ac.dfa.acipv6list.addresses);
if (!session->dfa.acipv6list.addresses->count && (session->dtls.localaddr.ss.ss_family == AF_INET6)) {
memcpy(capwap_array_get_item_pointer(session->dfa.acipv6list.addresses, 0), &session->dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
}
/* Init */
@ -610,73 +505,6 @@ static struct ac_session_t* ac_create_session(struct sockaddr_storage* wtpaddres
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 */
void ac_session_release_reference(struct ac_session_t* session) {
ASSERT(session != NULL);
@ -688,17 +516,6 @@ void ac_session_release_reference(struct ac_session_t* session) {
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 */
void ac_update_statistics(void) {
@ -816,15 +633,17 @@ int ac_execute(void) {
int index;
int check;
struct capwap_socket socket;
struct sockaddr_storage recvfromaddr;
struct sockaddr_storage recvtoaddr;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
struct ac_session_t* session;
char buffer[CAPWAP_MAX_PACKET_SIZE];
int buffersize;
struct ac_fds fds;
/* 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");
return AC_ERROR_SYSTEM_FAILER;
}
@ -837,14 +656,14 @@ int ac_execute(void) {
/* Start discovery thread */
if (!ac_discovery_start()) {
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
capwap_logging_debug("Unable to start discovery thread");
return AC_ERROR_SYSTEM_FAILER;
}
/* Enable Backend Management */
if (!ac_backend_start()) {
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
ac_discovery_stop();
capwap_logging_error("Unable start backend management");
return AC_ERROR_SYSTEM_FAILER;
@ -854,7 +673,7 @@ int ac_execute(void) {
while (g_ac.running) {
/* Receive packet */
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) {
capwap_logging_debug("Closing AC");
break;
@ -862,119 +681,62 @@ int ac_execute(void) {
/* */
if (index >= 0) {
/* Detect local address */
if (recvtoaddr.ss_family == AF_UNSPEC) {
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_ac.net.bind_interface, (!(g_ac.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
/* Search the AC session */
session = ac_search_session_from_wtpaddress(&fromaddr);
if (session) {
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, 0);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(g_ac.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
/* Release reference */
ac_session_release_reference(session);
} 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 */
capwap_get_network_socket(&g_ac.net, &socket, g_ac.fds.fdspoll[index].fd);
/* Get current session number */
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) {
struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr);
/* */
if (ac_backend_isconnect() && (sessioncount < g_ac.descriptor.maxwtp)) {
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) {
/* Add packet*/
ac_session_add_packet(session, buffer, buffersize, 0);
/* 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);
/* Release reference */
ac_session_release_reference(session);
} else {
unsigned short sessioncount;
if (type == CAPWAP_DISCOVERY_REQUEST) {
ac_discovery_add_packet(buffer, buffersize, fds.fdspoll[index].fd, &fromaddr);
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
/* 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 */
/* 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);
}
/* 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 {
struct ac_session_data_t* sessiondata = ac_search_session_data_from_wtpaddress(&recvfromaddr);
} 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(fds.fdspoll[index].fd, &fromaddr, &toaddr);
ac_session_add_packet(session, buffer, buffersize, 0);
if (sessiondata) {
/* Add packet*/
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;
/* Release reference */
ac_session_release_reference(session);
}
}
/* */
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)) {
/* Ignore recv */
continue;
@ -1000,6 +762,6 @@ int ac_execute(void) {
ac_backend_free();
/* Free file description pool */
ac_execute_free_fdspool(&g_ac.fds);
ac_execute_free_fdspool(&fds);
return result;
}

View File

@ -3,7 +3,7 @@
#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;
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;
struct ieee80211_ie_items ieitems;
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)) {
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) {
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 */
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;
@ -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);
if (responselength > 0) {
/* 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);
station->flags |= AC_STATION_FLAGS_AUTHENTICATED;
} else {
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 {
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)) {
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)) {
uint16_t algorithm;
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;
struct ieee80211_ie_items ieitems;
struct ac_station* station;
@ -149,7 +149,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Get station */
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) {
return;
}
@ -162,7 +162,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) {
/* Invalid station, delete station */
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;
}
@ -192,7 +192,7 @@ static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_data_
/* Parsing Information Elements */
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);
ac_stations_delete_station(sessiondata->session, station);
ac_stations_delete_station(session, station);
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);
if (responselength > 0) {
/* 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);
/* Active Station */
station->flags |= AC_STATION_FLAGS_ASSOCIATE;
ac_stations_authorize_station(sessiondata->session, station);
ac_stations_authorize_station(session, station);
} else {
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 {
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;
struct ieee80211_ie_items ieitems;
struct ac_station* station;
@ -269,7 +269,7 @@ static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_data
/* Get station */
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)) {
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 */
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;
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;
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;
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;
const uint8_t* stationaddress;
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);
/* Delete station */
station = ac_stations_get_station(sessiondata->session, radioid, NULL, stationaddress);
station = ac_stations_get_station(session, radioid, NULL, stationaddress);
if (station) {
station->flags &= ~(AC_STATION_FLAGS_AUTHORIZED | AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE);
ac_stations_delete_station(sessiondata->session, station);
/* Delete station without forward another IEEE802.11 deauthentication message */
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) {
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: {
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;
@ -375,7 +376,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: {
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;
@ -383,7 +384,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: {
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;
@ -391,7 +392,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: {
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;
@ -399,7 +400,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: {
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;
@ -407,7 +408,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: {
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;
@ -415,7 +416,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_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;
@ -423,7 +424,7 @@ static void ac_ieee80211_mgmt_packet(struct ac_session_data_t* sessiondata, uint
case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: {
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;
@ -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_type;
uint16_t framecontrol_subtype;
ASSERT(sessiondata != NULL);
ASSERT(session != NULL);
ASSERT(IS_VALID_RADIOID(radioid));
ASSERT(header != NULL);
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 */
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/family.h>
#include <netlink/genl/ctrl.h>
#include "ac_session.h"
#include "nlsmartcapwap.h"
/* 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) {
switch (gnlh->cmd) {
default: {
capwap_logging_debug("*** ac_kmod_event_handler: %d", (int)gnlh->cmd);
case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: {
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;
}
}
@ -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) {
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));
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);
}
@ -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;
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);
@ -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) {
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;
/* 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);
/* 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) {
capwap_logging_warning("Unable to found kernel module");
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);
/* Link to kernel module */
result = ac_kmod_link();
result = ac_kmod_link(hash, threads);
if (result) {
ac_kmod_free();
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);
/* */
int ac_kmod_isconnected(void);
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__ */

View File

@ -6,8 +6,8 @@
#include "ac_backend.h"
#include <arpa/inet.h>
#define AC_ERROR_TIMEOUT -1000
#define AC_ERROR_ACTION_SESSION -1001
#define AC_NO_ERROR -1000
#define AC_ERROR_TIMEOUT -1001
/* */
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);
/* 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;
ac_dfa_change_state(session, CAPWAP_RESET_STATE);
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);
}
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 */
if (!IS_VALID_RADIOID(notify->radioid) || !IS_VALID_WLANID(notify->wlanid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
#if 0
} else if (ac_wlans_get_bssid_with_wlanid(session, notify->radioid, notify->wlanid)) {
return AC_ERROR_ACTION_SESSION;
return AC_NO_ERROR;
#endif
}
@ -102,7 +102,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
capwap_packet_txmng_free(txmngpacket);
/* 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;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -111,7 +111,7 @@ static int ac_session_action_addwlan(struct ac_session_t* session, struct ac_not
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 */
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);
/* 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;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -176,7 +176,7 @@ static int ac_session_action_station_configuration_ieee8011_add_station(struct a
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 */
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);
/* 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;
capwap_timeout_set(session->timeout, session->idtimercontrol, AC_RETRANSMIT_INTERVAL, ac_dfa_retransmition_timeout, session, NULL);
} else {
@ -225,12 +225,25 @@ static int ac_session_action_station_configuration_ieee8011_delete_station(struc
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) {
int result = AC_ERROR_ACTION_SESSION;
int result = AC_NO_ERROR;
switch (action->action) {
case AC_SESSION_ACTION_CLOSE: {
@ -248,24 +261,43 @@ static int ac_session_action_execute(struct ac_session_t* session, struct ac_ses
break;
}
case AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA: {
int valid = 0;
struct ac_soap_response* response;
case AC_SESSION_ACTION_RECV_KEEPALIVE: {
#ifdef DEBUG
{
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 (response) {
valid = ((response->responsecode == HTTP_RESULT_OK) ? 1 : 0);
ac_soapclient_free_response(response);
/* */
if (session->state == CAPWAP_DATA_CHECK_TO_RUN_STATE) {
struct ac_soap_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) {
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;
}
break;
}
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;
}
@ -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);
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;
@ -324,8 +368,6 @@ static int ac_network_read(struct ac_session_t* session, void* buffer, int lengt
} else if (session->packets->count > 0) {
struct capwap_list_item* itempacket;
capwap_logging_debug("Receive control packet");
/* Get packet */
itempacket = capwap_itemlist_remove_head(session->packets);
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 (session->state == CAPWAP_DTLS_CONNECT_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;
}
case CAPWAP_DATA_CHECK_TO_RUN_STATE: {
ac_dfa_state_datacheck_to_run(session, packet);
break;
}
case CAPWAP_RUN_STATE: {
ac_dfa_state_run(session, packet);
break;
@ -472,7 +509,7 @@ static void ac_send_invalid_request(struct ac_session_t* session, uint32_t error
capwap_packet_txmng_free(txmngpacket);
/* 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 */
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);
#endif
/* Release session data reference */
if (session->sessiondata) {
ac_session_data_close(session->sessiondata);
ac_session_data_release_reference(session->sessiondata);
}
/* Release last reference */
capwap_lock_enter(&session->sessionlock);
session->count--;
@ -523,6 +554,9 @@ static void ac_session_destroy(struct ac_session_t* session) {
capwap_lock_exit(&session->sessionlock);
/* Close data channel */
ac_kmod_delete_datasession(&session->sockaddrdata.ss, &session->sessionid);
/* Free DTSL Control */
capwap_crypt_freesession(&session->dtls);
@ -563,38 +597,6 @@ static void ac_session_destroy(struct ac_session_t* session) {
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) {
int res;
@ -605,9 +607,6 @@ static void ac_session_run(struct ac_session_t* session) {
ASSERT(session != NULL);
/* */
ac_session_report_connection(session);
/* Configure DFA */
if (g_ac.enabledtls) {
if (!ac_dtls_setup(session)) {
@ -616,7 +615,7 @@ static void ac_session_run(struct ac_session_t* session) {
} else {
/* Wait Join request */
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) {
@ -628,24 +627,31 @@ static void ac_session_run(struct ac_session_t* session) {
}
} else if (length > 0) {
/* 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) {
struct capwap_parsed_packet packet;
/* Defragment management */
if (!session->rxmngpacket) {
session->rxmngpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET);
session->rxmngpacket = capwap_packet_rxmng_create_message();
}
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(session->rxmngpacket, buffer, length);
if (check == CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* 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 */
res = capwap_check_message_type(session->rxmngpacket);
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) {
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);
}
}
} else {
capwap_logging_debug("Retrasmitted control packet");
}
/* 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);
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) {
struct capwap_list* addrlist;
int count;
struct capwap_list_item* item;
ASSERT(controllist != NULL);
/* Detect local address */
addrlist = capwap_list_create();
capwap_interface_list(&g_ac.net, addrlist);
/* */
capwap_rwlock_rdlock(&g_ac.sessionslock);
count = g_ac.sessions->count;
capwap_rwlock_exit(&g_ac.sessionslock);
/* 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 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));
sessioncontrol = (struct ac_session_control*)itemcontrol->item;
memcpy(&sessioncontrol->localaddress, address, sizeof(struct sockaddr_storage));
sessioncontrol->count = 0;
memcpy(&sessioncontrol->localaddress, address, sizeof(union sockaddr_capwap));
sessioncontrol->count = count;
/* Add */
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);
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;
if (!session->requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet");
ac_session_teardown(session);
} else {
session->retransmitcount++;
if (session->retransmitcount >= AC_MAX_RETRANSMIT) {
capwap_logging_info("Retransmition request packet timeout");
/* Timeout reset state */
ac_free_reference_last_request(session);
ac_session_teardown(session);
} else {
/* Retransmit Reset Request */
/* Retransmit Request */
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");
}
@ -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) {
capwap_logging_info("Session timeout, teardown");
ac_session_teardown((struct ac_session_t*)context);
}

View File

@ -15,23 +15,23 @@ struct ac_packet {
/* */
struct ac_session_control {
struct sockaddr_storage localaddress;
union sockaddr_capwap localaddress;
unsigned short count;
};
/* */
#define AC_SESSION_ACTION_CLOSE 0
#define AC_SESSION_ACTION_RESET_WTP 1
#define AC_SESSION_ACTION_ESTABLISHED_SESSION_DATA 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_ACTION_NOTIFY_EVENT 2
#define AC_SESSION_DATA_ACTION_ROAMING_STATION 1
#define AC_SESSION_DATA_ACTION_ASSIGN_BSSID 2
#define AC_SESSION_DATA_ACTION_ADD_STATION_STATUS 3
#define AC_SESSION_DATA_ACTION_DELETE_STATION_STATUS 4
#define AC_SESSION_ACTION_RECV_KEEPALIVE 10
#define AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET 11
#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 {
@ -94,56 +94,8 @@ struct ac_notify_station_configuration_ieee8011_delete_station {
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_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 */
struct ac_session_t {
@ -166,17 +118,18 @@ struct ac_session_t {
unsigned long state;
struct ac_state dfa;
/* */
unsigned short binding;
struct ac_session_data_t* sessiondata;
struct capwap_sessionid_element sessionid;
int teardown;
unsigned short mtu;
struct capwap_dtls dtls;
struct capwap_connection connection;
union sockaddr_capwap sockaddrdata;
struct capwap_timeout* timeout;
unsigned long idtimercontrol;
unsigned long idtimerkeepalivedead;
capwap_event_t waitpacket;
capwap_lock_t sessionlock;
@ -185,14 +138,16 @@ struct ac_session_t {
struct capwap_list* notifyevent;
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;
uint8_t localseqnumber;
struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount;
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
};
/* 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_release_reference(struct ac_session_t* session);
/* Session data */
void* ac_session_data_thread(void* param);
void ac_session_data_close(struct ac_session_data_t* sessiondata);
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);
/* */
struct ac_session_t* ac_search_session_from_sessionid(struct capwap_sessionid_element* sessionid);
int ac_has_sessionid(struct capwap_sessionid_element* sessionid);
/* */
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);
int ac_has_wtpid(const char* wtpid);
/* */
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_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);
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_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);
@ -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_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_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_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_reset(struct ac_session_t* session, struct capwap_parsed_packet* packet);
void ac_dfa_state_teardown(struct ac_session_t* session);
/* 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;
/* 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) {
ac_soapclient_close_request(httprequest, 0);
return NULL;

View File

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

View File

@ -42,7 +42,7 @@ static void ac_stations_reset_station(struct ac_session_t* session, struct ac_st
/* Remove timers */
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;
}
@ -153,7 +153,6 @@ int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) {
/* */
wlan->session = session;
wlan->sessiondata = session->sessiondata;
/* Create WLAN list */
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) {
/* Release station from old owner */
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 */
@ -411,7 +410,7 @@ void ac_stations_authorize_station(struct ac_session_t* session, struct ac_stati
ASSERT(session->wlans != 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)) {
memset(&notify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station));
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);
if (responselength > 0) {
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 */
struct ac_session_t* session;
struct ac_session_data_t* sessiondata;
uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE];

View File

@ -4,7 +4,10 @@ obj-m += smartcapwap.o
smartcapwap-y := \
main.o \
netlinkapp.o
netlinkapp.o \
capwap.o \
capwap_private.o \
socket.o
all:
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/kernel.h>
#include "netlinkapp.h"
/* */
static int __init smartcapwap_ac_init(void) {
int result = 0;
int ret;
/* */
result = nlsmartcapwap_ac_init();
TRACEKMOD("### smartcapwap_ac_init\n");
return result;
/* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
}
module_init(smartcapwap_ac_init);
/* */
static void __exit smartcapwap_ac_exit(void) {
nlsmartcapwap_ac_exit();
TRACEKMOD("### smartcapwap_ac_exit\n");
sc_netlink_exit();
}
module_exit(smartcapwap_ac_exit);

View File

@ -1,5 +1,8 @@
#include "config.h"
#include <linux/module.h>
#include <linux/version.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <net/genetlink.h>
@ -9,90 +12,251 @@
#include <linux/ieee80211.h>
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#include "capwap.h"
/* */
struct nlsmartcapwap_ac_device {
struct list_head list;
u32 usermodeid;
};
static u32 sc_netlink_usermodeid;
/* */
static u32 nlsmartcapwap_ac_usermodeid = 0;
static LIST_HEAD(nlsmartcapwap_ac_dev_list);
/* 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
static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_pre_doit\n");
rtnl_lock();
return 0;
}
if (!nlsmartcapwap_ac_usermodeid) {
nlsmartcapwap_ac_usermodeid = portid;
} else if (nlsmartcapwap_ac_usermodeid == portid) {
ret = -EALREADY;
} else {
ret = -EBUSY;
}
/* */
static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_post_doit\n");
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;
}
/* */
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;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
u32 portid = notify->pid;
#else
u32 portid = notify->portid;
#endif
/* */
if (state == NETLINK_URELEASE) {
rtnl_lock();
if (nlsmartcapwap_ac_usermodeid == portid) {
nlsmartcapwap_ac_usermodeid = 0;
if (sc_netlink_usermodeid == notify->portid) {
/* Close capwap engine */
sc_capwap_close();
/* Close all devices */
nlsmartcapwap_ac_close();
/* Allow unload module */
module_put(THIS_MODULE);
sc_netlink_usermodeid = 0;
}
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] = {
[NLSMARTCAPWAP_AC_ATTR_FLAGS] = { .type = NLA_U32 },
static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[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 */
static struct genl_ops nlsmartcapwap_ac_ops[] = {
static struct genl_ops sc_netlink_ops[] = {
{
.cmd = NLSMARTCAPWAP_AC_CMD_LINK,
.doit = nlsmartcapwap_ac_link,
.policy = nlsmartcapwap_ac_policy,
.cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = sc_netlink_link,
.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,
},
};
/* Netlink notify */
static struct notifier_block nlsmartcapwap_ac_netlink_notifier = {
.notifier_call = nlsmartcapwap_ac_netlink_notify,
static struct notifier_block sc_netlink_notifier = {
.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;
TRACEKMOD("### sc_netlink_init\n");
/* */
sc_netlink_usermodeid = 0;
/* Register netlink family */
#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
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
if (ret) {
return ret;
goto error;
}
/* Register netlink notifier */
ret = netlink_register_notifier(&nlsmartcapwap_ac_netlink_notifier);
ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) {
genl_unregister_family(&nlsmartcapwap_ac_family);
return ret;
goto error2;
}
return 0;
error2:
genl_unregister_family(&sc_netlink_family);
error:
return ret;
}
/* */
void nlsmartcapwap_ac_exit(void) {
/* */
rtnl_lock();
nlsmartcapwap_ac_close();
rtnl_unlock();
void sc_netlink_exit(void) {
TRACEKMOD("### sc_netlink_exit\n");
/* */
netlink_unregister_notifier(&nlsmartcapwap_ac_netlink_notifier);
genl_unregister_family(&nlsmartcapwap_ac_family);
netlink_unregister_notifier(&sc_netlink_notifier);
genl_unregister_family(&sc_netlink_family);
}

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_AC_NETLINKAPP_HEADER__
#define __KMOD_AC_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
int nlsmartcapwap_ac_init(void);
void nlsmartcapwap_ac_exit(void);
int sc_netlink_init(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__ */

View File

@ -2,28 +2,55 @@
#define __AC_NLSMARTCAPWAP_HEADER__
/* */
#define SMARTCAPWAP_AC_GENL_NAME "smartcapwap_ac"
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac"
/* */
enum nlsmartcapwap_ac_attrs {
NLSMARTCAPWAP_AC_ATTR_UNSPEC,
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
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 */
__NLSMARTCAPWAP_AC_ATTR_AFTER_LAST,
NLSMARTCAPWAP_AC_ATTR_MAX = __NLSMARTCAPWAP_AC_ATTR_AFTER_LAST - 1
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
};
/* */
enum nlsmartcapwap_ac_commands {
NLSMARTCAPWAP_AC_CMD_UNSPEC,
enum sc_netlink_commands {
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 */
__NLSMARTCAPWAP_AC_CMD_AFTER_LAST,
NLSMARTCAPWAP_AC_CMD_MAX = __NLSMARTCAPWAP_AC_CMD_AFTER_LAST - 1
__NLSMARTCAPWAP_CMD_AFTER_LAST,
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
};
#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_error.h"
#define CANARY 0xaaaaaaaa
#define BACKTRACE_BUFFER 256
#ifndef DEBUG_BREAKPOINT
@ -46,8 +45,8 @@ void* capwap_alloc_debug(size_t size, const char* file, const int line) {
exit(CAPWAP_ASSERT_CONDITION);
}
/* Alloc block with memory block and canary */
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size + 4);
/* Alloc block with memory block */
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size);
if (!block) {
capwap_logging_debug("Out of memory %s(%d)", file, line);
DEBUG_BREAKPOINT();
@ -64,9 +63,6 @@ void* capwap_alloc_debug(size_t size, const char* file, const int line) {
#endif
block->next = g_memoryblocks;
/* Canary */
*((unsigned long*)(((char*)block->item) + block->size)) = CANARY;
g_memoryblocks = block;
return block->item;
@ -98,13 +94,6 @@ void capwap_free_debug(void* p, const char* file, const int line) {
return;
}
/* Check canary */
if (*((unsigned long*)(((char*)block->item) + block->size)) != CANARY) {
capwap_logging_debug("%s(%d): Invalid canary allocted in %s(%d)", file, line, block->file, block->line);
DEBUG_BREAKPOINT();
return;
}
/* Find memory block */
prevblock = NULL;
findblock = g_memoryblocks;

View File

@ -22,7 +22,7 @@ void capwap_dump_memory(void);
#ifdef USE_DEBUG_BACKTRACE
void capwap_backtrace_callstack(void);
#else
#define capwap_backtrace_callstack() (0)
#define capwap_backtrace_callstack()
#endif
#else
@ -34,9 +34,9 @@ void capwap_backtrace_callstack(void);
/* Standard memory management */
#define capwap_alloc(l) ({ void* __x = malloc(l); if (!__x) capwap_outofmemory(); __x; })
#define capwap_free(x) free(x)
#define capwap_check_memory_leak(x) (0)
#define capwap_dump_memory() (0)
#define capwap_backtrace_callstack() (0)
#define capwap_check_memory_leak(x)
#define capwap_dump_memory()
#define capwap_backtrace_callstack()
#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);
/* 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;
}
@ -196,18 +196,14 @@ static int capwap_crypt_createcookie(CYASSL* ssl, unsigned char* buffer, int siz
}
/* Create buffer with peer's address and port */
if (dtls->peeraddr.ss_family == AF_INET) {
struct sockaddr_in* peeripv4 = (struct sockaddr_in*)&dtls->peeraddr;
if (dtls->peeraddr.ss.ss_family == AF_INET) {
length = sizeof(struct in_addr) + sizeof(in_port_t);
memcpy(temp, &peeripv4->sin_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &peeripv4->sin_addr, sizeof(struct in_addr));
} else if (dtls->peeraddr.ss_family == AF_INET6) {
struct sockaddr_in6* peeripv6 = (struct sockaddr_in6*)&dtls->peeraddr;
memcpy(temp, &dtls->peeraddr.sin.sin_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &dtls->peeraddr.sin.sin_addr, sizeof(struct in_addr));
} else if (dtls->peeraddr.ss.ss_family == AF_INET6) {
length = sizeof(struct in6_addr) + sizeof(in_port_t);
memcpy(temp, &peeripv6->sin6_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &peeripv6->sin6_addr, sizeof(struct in6_addr));
memcpy(temp, &dtls->peeraddr.sin6.sin6_port, sizeof(in_port_t));
memcpy(temp + sizeof(in_port_t), &dtls->peeraddr.sin6.sin6_addr, sizeof(struct in6_addr));
} else {
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(dtlscontext != NULL);
ASSERT(dtlscontext->sslcontext != NULL);
ASSERT(biosend != NULL);
memset(dtls, 0, sizeof(struct capwap_dtls));
/* Create ssl session */
dtls->sslsession = (void*)CyaSSL_new((CYASSL_CTX*)dtlscontext->sslcontext);
if (!dtls->sslsession) {
@ -391,10 +384,6 @@ int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct
return 0;
}
/* Send callback */
dtls->send = biosend;
dtls->sendparam = param;
/* */
CyaSSL_set_using_nonblock((CYASSL*)dtls->sslsession, 1);
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->session = sessiontype;
dtls->dtlscontext = dtlscontext;
dtls->enable = 1;
dtls->buffer = NULL;
dtls->length = 0;
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) {
memcpy(&dtls->peeraddr, peeraddr, sizeof(struct sockaddr_storage));
void capwap_crypt_setconnection(struct capwap_dtls* dtls, int sock, union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr) {
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);
}
@ -473,15 +483,15 @@ void capwap_crypt_freesession(struct capwap_dtls* 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) {
ASSERT(sock >= 0);
/* */
int capwap_crypt_sendto(struct capwap_dtls* dtls, void* buffer, int size) {
ASSERT(dtls != NULL);
ASSERT(dtls->sock >= 0);
ASSERT(buffer != NULL);
ASSERT(size > 0);
ASSERT(sendtoaddr != NULL);
if (!dtls || !dtls->enable) {
return capwap_sendto(sock, buffer, size, sendfromaddr, sendtoaddr);
if (!dtls->enable) {
return capwap_sendto(dtls->sock, buffer, size, &dtls->peeraddr);
}
/* 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;
ASSERT(sock >= 0);
ASSERT(dtls != NULL);
ASSERT(dtls->sock >= 0);
ASSERT(fragmentlist != NULL);
ASSERT(sendtoaddr != NULL);
item = fragmentlist->first;
while (item) {
@ -506,7 +516,7 @@ int capwap_crypt_sendto_fragmentpacket(struct capwap_dtls* dtls, int sock, struc
ASSERT(fragmentpacket != NULL);
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;
}
@ -536,7 +546,7 @@ int capwap_decrypt_packet(struct capwap_dtls* dtls, void* encrybuffer, int size,
if (!plainbuffer) {
clone = capwap_clone(encrybuffer, size);
}
dtls->buffer = (clone ? clone : encrybuffer);
dtls->length = size;

View File

@ -2,6 +2,7 @@
#define __CAPWAP_DTLS_HEADER__
#include "capwap_list.h"
#include "capwap_network.h"
#define CAPWAP_DTLS_CLIENT 0
#define CAPWAP_DTLS_SERVER 1
@ -20,16 +21,12 @@
#define CAPWAP_HANDSHAKE_CONTINUE 0
#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_SHUTDOWN -1
#define CAPWAP_ERROR_CLOSE -2
/* */
struct capwap_dtls;
typedef int(*capwap_bio_send)(struct capwap_dtls* dtls, char* buffer, int length, void* param);
/* */
struct capwap_dtls_context {
@ -51,15 +48,15 @@ struct capwap_dtls_context {
struct capwap_dtls {
int enable;
int action;
int session;
/* */
void* sslsession;
struct capwap_dtls_context* dtlscontext;
/* Send callback */
struct sockaddr_storage peeraddr;
capwap_bio_send send;
void* sendparam;
/* */
int sock;
union sockaddr_capwap localaddr;
union sockaddr_capwap peeraddr;
/* Buffer read */
void* buffer;
@ -94,14 +91,15 @@ void capwap_crypt_free();
int capwap_crypt_createcontext(struct capwap_dtls_context* dtlscontext, struct capwap_dtls_param* param);
void capwap_crypt_freecontext(struct capwap_dtls_context* dtlscontext);
int capwap_crypt_createsession(struct capwap_dtls* dtls, int sessiontype, struct capwap_dtls_context* dtlscontext, capwap_bio_send biosend, void* param);
void capwap_crypt_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);
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);
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_fragmentpacket(struct capwap_dtls* dtls, int sock, struct capwap_list* fragmentlist, 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, struct capwap_list* fragmentlist);
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);

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 bodylength;
ASSERT(rxmngpacket != 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));
packet->rxmngpacket = rxmngpacket;
packet->connection = connection;
packet->messages = capwap_list_create();
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 */
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;
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)) {
/* */
bodylength = rxmngpacket->ctrlmsg.length - CAPWAP_CONTROL_MESSAGE_MIN_LENGTH;
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;
unsigned short bodylength = rxmngpacket->datamsg.length - CAPWAP_DATA_MESSAGE_KEEPALIVE_MIN_LENGTH;
/* Get type and length */
rxmngpacket->readerpacketallowed = sizeof(struct capwap_message_element);
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &type);
rxmngpacket->read_ops.read_u16((capwap_message_elements_handle)rxmngpacket, &msglength);
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 + 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;
}
/* Allowed to parsing only the size of message element */
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 */
read_ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_SESSIONID);
itemlist = capwap_itemlist_create(sizeof(struct capwap_message_element_itemlist));
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;
/* Check if read all data of message element */
if (rxmngpacket->readerpacketallowed) {
return INVALID_MESSAGE_ELEMENT;
}
/* */
capwap_itemlist_insert_after(packet->messages, NULL, itemlist);
bodylength -= (msglength + sizeof(struct capwap_message_element));
}
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) {
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);
if (packet->rxmngpacket->isctrlpacket) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_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)) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_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 {
if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)) {
return 0;
}
}
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)) {
} else {
return 0;
}
break;
}
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;
}
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;
}
break;
}
} else {
/* Keep alive data message require session id */
if (IS_FLAG_K_HEADER(packet->rxmngpacket->header)) {
if (capwap_get_message_element(packet, CAPWAP_ELEMENT_SESSIONID)) {
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;
}
} else {
/* Validate Radio ID */
uint8_t radioid = GET_RID_HEADER(packet->rxmngpacket->header);
if (IS_VALID_RADIOID(radioid)) {
break;
}
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;
}
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);
packet->messages = NULL;
}
/* */
packet->connection = NULL;
}

View File

@ -131,7 +131,6 @@ struct capwap_message_element_itemlist {
struct capwap_parsed_packet {
struct capwap_packet_rxmng* rxmngpacket;
struct capwap_connection* connection;
struct capwap_list* messages;
};
@ -140,13 +139,11 @@ struct capwap_parsed_packet {
#define UNRECOGNIZED_MESSAGE_ELEMENT 1
#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);
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);
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__ */

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_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
#define CAPWAP_SOCKET_IPV4_UDP 0
#define CAPWAP_SOCKET_IPV4_UDPLITE 1
#define CAPWAP_SOCKET_IPV6_UDP 2
#define CAPWAP_SOCKET_IPV6_UDPLITE 3
union sockaddr_capwap {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
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_TIMEOUT -2
#define CAPWAP_RECV_ERROR_INTR -3
/* Socket Flags */
#define CAPWAP_IPV6ONLY_FLAG 0x00000001
/* Network struct */
struct capwap_network {
int sock_family; /* Address family used by the server. */
unsigned short bind_sock_ctrl_port; /* Port number to listen control protocol. */
char bind_interface[IFNAMSIZ];
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;
union sockaddr_capwap localaddr;
char bindiface[IFNAMSIZ];
int socket;
};
void capwap_network_init(struct capwap_network* net);
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);
int capwap_get_macaddress_from_interface(const char* interface, char* macaddress);
#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_network_get_localaddress(union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr, char* iface);
int capwap_bind_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_fragmentpacket(int sock, struct capwap_list* fragmentlist, 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, union sockaddr_capwap* toaddr);
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(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr, struct capwap_timeout* timeout);
int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr);
int capwap_ipv4_mapped_ipv6(struct sockaddr_storage* source, struct sockaddr_storage* dest);
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);
int capwap_address_from_string(const char* ip, union sockaddr_capwap* sockaddr);
char* capwap_printf_macaddress(char* buffer, const uint8_t* macaddress, 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_list.h"
#include "capwap_array.h"
#include "md5.h"
/* 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;
ASSERT(buffer != NULL);
@ -18,43 +17,28 @@ int capwap_sanity_check(int isctrlsocket, int state, void* buffer, int buffersiz
return CAPWAP_WRONG_PACKET;
}
if (isctrlsocket) {
if (dtlsctrlenable) {
if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) {
if (state == CAPWAP_DISCOVERY_STATE) {
if (dtlsenable) {
if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) {
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_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_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;
}
return CAPWAP_PLAIN_PACKET;
}
}
} else {
if (dtlsdataenable) {
if ((preamble->type == CAPWAP_PREAMBLE_DTLS_HEADER) && (buffersize >= sizeof(struct capwap_dtls_header))) {
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) {
return CAPWAP_PLAIN_PACKET;
}
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;
}
/* 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 */
int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket) {
unsigned short lengthpayload;
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_header* header = (struct capwap_header*)packet->buffer;
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;
}
}
} else if (!rxmngpacket->isctrlpacket && rxmngpacket->fragmentlist->first) {
return VALID_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;
fragmentpacket->offset = available + packetpos;
if (txmngpacket->isctrlpacket) {
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));
}
txmngpacket->ctrlmsg->length = htons(ntohs(txmngpacket->ctrlmsg->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);
/* Create message */
txmngpacket->isctrlpacket = 1;
txmngpacket->ctrlmsg = (struct capwap_control_message*)&fragmentpacket->buffer[fragmentpacket->offset];
txmngpacket->ctrlmsg->type = htonl(type);
txmngpacket->ctrlmsg->seq = seq;
@ -574,52 +484,6 @@ struct capwap_packet_txmng* capwap_packet_txmng_create_ctrl_message(struct capwa
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) {
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;
/* */
rxmngpacket = (struct capwap_packet_rxmng*)capwap_alloc(sizeof(struct capwap_packet_rxmng));
memset(rxmngpacket, 0, sizeof(struct capwap_packet_rxmng));
rxmngpacket->isctrlpacket = isctrlpacket;
/* Fragment bucket */
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;
/* Read message type */
if (rxmngpacket->isctrlpacket) {
rxmngpacket->readerpacketallowed = sizeof(struct capwap_control_message);
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_u16((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.length);
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);
}
rxmngpacket->readerpacketallowed = sizeof(struct capwap_control_message);
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_u16((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.length);
rxmngpacket->read_ops.read_u8((capwap_message_elements_handle)rxmngpacket, &rxmngpacket->ctrlmsg.flags);
/* Position of capwap body */
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;

View File

@ -16,7 +16,7 @@
#define CAPWAP_NONE_PACKET 0
#define CAPWAP_PLAIN_PACKET 1
#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 */
struct capwap_fragment_packet_item {
@ -50,11 +50,7 @@ struct capwap_packet_txmng {
struct capwap_header* header;
/* Capwap message */
int isctrlpacket;
union {
struct capwap_control_message* ctrlmsg;
struct capwap_data_message* datamsg;
};
struct capwap_control_message* ctrlmsg;
/* Write functions */
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_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_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);
@ -83,11 +77,7 @@ struct capwap_packet_rxmng {
struct capwap_header* header;
/* Capwap message */
int isctrlpacket;
union {
struct capwap_control_message ctrlmsg;
struct capwap_data_message datamsg;
};
struct capwap_control_message ctrlmsg;
/* Position of message elements or binding data */
struct read_block_from_pos readbodypos;
@ -106,10 +96,7 @@ struct capwap_packet_rxmng {
#define CAPWAP_REQUEST_MORE_FRAGMENT 0
#define CAPWAP_RECEIVE_COMPLETE_PACKET 1
#define CAPWAP_CONTROL_PACKET 1
#define CAPWAP_DATA_PACKET 0
struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(int isctrlpacket);
struct capwap_packet_rxmng* capwap_packet_rxmng_create_message(void);
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);
@ -125,8 +112,4 @@ int capwap_is_request_type(unsigned long type);
#define INVALID_REQUEST_MESSAGE_TYPE 2
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__ */

View File

@ -1,4 +1,5 @@
#include "capwap.h"
#include "capwap_network.h"
#include "capwap_socket.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;
struct pollfd fds;
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 (errno == EINPROGRESS) {
/* Wait to connection complete */

View File

@ -2,7 +2,7 @@
#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_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 "wifi_drivers.h"
#include "wtp_radio.h"
#include "wtp_kmod.h"
/* Declare enable wifi driver */
#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);
/* 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 {
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 enable Split Mac send the probe request message to AC */
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 {
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);
/* 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 */
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) {
capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress);
wifi_station_delete(station);
@ -596,7 +597,7 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
wifi_station_delete(station);
}
} 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);
/* 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 */
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 {
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);
@ -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);
}
} 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->capability = __le16_to_cpu(frame->associationresponse.capability);
@ -729,7 +730,7 @@ static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan
/* TODO */
/* 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 */
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->macmode = params->macmode;
wlan->tunnelmode = params->tunnelmode;
wlan->send_frame = params->send_frame;
wlan->send_frame_to_ac_cbparam = params->send_frame_to_ac_cbparam;
wlan->radioid = params->radioid;
wlan->wlanid = params->wlanid;
/* Start AP */
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->handle != NULL);
if (!data || (length <= 0) || !wlan->send_frame) {
if (!data || (length <= 0)) {
return -1;
}
/* */
return wlan->send_frame(wlan->send_frame_to_ac_cbparam, data, length, nativeframe, rssi, snr, rate, wlan->address, MACADDRESS_EUI48_LENGTH);
/* Send packet to AC */
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;
ASSERT(device != NULL);
ASSERT(address != NULL);
/* Get station */
/* */
station = wifi_station_get(NULL, address);
if (!station || !station->wlan) {
return -1;
if (station && station->wlan) {
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 {
send_frame_to_ac send_frame;
void* send_frame_to_ac_cbparam;
uint8_t radioid;
uint8_t wlanid;
const char* ssid;
uint8_t ssid_hidden;
@ -289,8 +289,8 @@ struct wifi_wlan {
uint8_t address[MACADDRESS_EUI48_LENGTH];
/* */
send_frame_to_ac send_frame;
void* send_frame_to_ac_cbparam;
uint8_t radioid;
uint8_t wlanid;
/* WLAN information */
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);
int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid);
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);
/* WLAN packet management */
@ -419,7 +419,7 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
/* Station management */
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 */
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;
}
/* */
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);
@ -798,16 +799,13 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
/* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* Join interface to kernel module */
if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) {
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);
/* Join interface in kernel module */
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)) {
capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex);
}
if (!wtp_kmod_join_mac80211_device(wlan, flags)) {
capwap_logging_info("Joined the interface %d in kernel mode ", wlan->virtindex);
} 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;
}
}
@ -833,9 +831,7 @@ static void nl80211_wlan_stopap(struct wifi_wlan* wlan) {
/* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* 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);
return result;

View File

@ -2,4 +2,7 @@ obj-m += smartcapwap.o
smartcapwap-y := \
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/kernel.h>
#include "netlinkapp.h"
/* */
static int __init smartcapwap_init(void) {
int result = 0;
static int __init smartcapwap_wtp_init(void) {
int ret;
/* */
result = nlsmartcapwap_init();
TRACEKMOD("### smartcapwap_wtp_init\n");
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) {
nlsmartcapwap_exit();
static void __exit smartcapwap_wtp_exit(void) {
TRACEKMOD("### smartcapwap_wtp_exit\n");
sc_netlink_exit();
}
module_exit(smartcapwap_exit);
module_exit(smartcapwap_wtp_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");

View File

@ -1,5 +1,7 @@
#include "config.h"
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <net/genetlink.h>
#include <linux/rcupdate.h>
@ -8,154 +10,200 @@
#include <linux/ieee80211.h>
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#include "capwap.h"
/* */
struct nlsmartcapwap_device {
struct sc_netlink_device {
struct list_head list;
struct ieee80211_pcktunnel pcktunnel_handler;
u32 usermodeid;
u32 ifindex;
u32 flags;
uint32_t ifindex;
uint8_t radioid;
uint8_t wlanid;
uint8_t binding;
struct net_device* dev;
uint32_t flags;
};
/* */
static u32 nlsmartcapwap_usermodeid = 0;
static LIST_HEAD(nlsmartcapwap_dev_list);
static uint32_t sc_netlink_usermodeid;
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();
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();
}
/* Netlink Family */
static struct genl_family nlsmartcapwap_family = {
static struct genl_family sc_netlink_family = {
.id = GENL_ID_GENERATE,
.name = SMARTCAPWAP_GENL_NAME,
.name = NLSMARTCAPWAP_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_ATTR_MAX,
.netnsok = true,
.pre_doit = nlsmartcapwap_pre_doit,
.post_doit = nlsmartcapwap_post_doit,
.pre_doit = sc_netlink_pre_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) {
int result = 0;
int frame8023 = 0;
struct nlsmartcapwap_device* nldev = (struct nlsmartcapwap_device*)data;
static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) {
int ret = 0;
struct sc_netlink_device* nldev = (struct sc_netlink_device*)data;
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data;
TRACEKMOD("### sc_netlink_handler\n");
/* IEEE802.11 Data Packet */
if (ieee80211_is_data(hdr->frame_control)) {
if ((nldev->flags & SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME) && ieee80211_is_data_present(hdr->frame_control)) {
result = -1;
int err;
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 */
if (nldev->flags & SMARTCAPWAP_FLAGS_TUNNEL_8023) {
frame8023 = 1;
}
}
/* */
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);
/* IEEE 802.11 into IEEE 802.3 */
if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) {
if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) {
printk("*** convertion error\n");
goto error;
}
/* 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) {
struct nlsmartcapwap_device* nldev;
static struct sc_netlink_device* sc_netlink_new_device(uint32_t ifindex, uint8_t radioid, u8 wlanid, uint8_t binding) {
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 */
nldev = (struct nlsmartcapwap_device*)kzalloc(sizeof(struct nlsmartcapwap_device), GFP_KERNEL);
if (nldev) {
/* Initialize device */
nldev->pcktunnel_handler.handler = nlsmartcapwap_handler;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
nldev = (struct sc_netlink_device*)kzalloc(sizeof(struct sc_netlink_device), GFP_KERNEL);
if (!nldev) {
dev_put(dev);
return NULL;
}
/* 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;
}
/* */
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 */
ieee80211_pcktunnel_deregister(nldev->ifindex, &nldev->pcktunnel_handler);
ieee80211_pcktunnel_deregister(nldev->dev, &nldev->pcktunnel_handler);
/* */
dev_put(nldev->dev);
/* Free memory */
kfree(nldev);
}
/* */
static struct nlsmartcapwap_device* nlsmartcapwap_register_device(u32 ifindex) {
struct nlsmartcapwap_device* nldev;
static struct sc_netlink_device* sc_netlink_register_device(uint32_t ifindex, uint8_t radioid, uint16_t wlanid, uint8_t binding) {
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_register_device\n");
ASSERT_RTNL();
/* */
if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) {
return NULL;
}
/* 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) {
return nldev;
return NULL;
}
}
/* Create device */
nldev = nlsmartcapwap_new_device(ifindex);
nldev = sc_netlink_new_device(ifindex, radioid, wlanid, binding);
if (nldev) {
list_add_rcu(&nldev->list, &nlsmartcapwap_dev_list);
list_add_rcu(&nldev->list, &sc_netlink_dev_list);
}
return nldev;
}
/* */
static int nlsmartcapwap_unregister_device(u32 ifindex) {
static int sc_netlink_unregister_device(uint32_t ifindex) {
int ret = -ENODEV;
struct nlsmartcapwap_device* nldev;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_unregister_device\n");
ASSERT_RTNL();
/* 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) {
/* Remove from list */
list_del_rcu(&nldev->list);
@ -163,7 +211,7 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
/* Free device */
ret = 0;
nlsmartcapwap_free_device(nldev);
sc_netlink_free_device(nldev);
break;
}
}
@ -172,27 +220,43 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
}
/* */
static void nlsmartcapwap_close(void) {
struct nlsmartcapwap_device* nldev;
struct nlsmartcapwap_device* tmp;
static void sc_netlink_unregister_alldevice(void) {
struct sc_netlink_device* tmp;
struct sc_netlink_device* nldev;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_dev_list, list) {
list_del(&nldev->list);
TRACEKMOD("### sc_netlink_unregister_alldevice\n");
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 */
nlsmartcapwap_free_device(nldev);
sc_netlink_free_device(nldev);
}
}
/* */
static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
u32 portid = genl_info_snd_portid(info);
static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint32_t portid = genl_info_snd_portid(info);
if (!nlsmartcapwap_usermodeid) {
nlsmartcapwap_usermodeid = portid;
} else if (nlsmartcapwap_usermodeid == portid) {
TRACEKMOD("### sc_netlink_link\n");
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;
} else {
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) {
struct netlink_notify* notify = (struct netlink_notify*)_notify;
u32 portid = netlink_notify_portid(notify);
static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info) {
/* Check Link */
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) {
rtnl_lock();
if (nlsmartcapwap_usermodeid == portid) {
nlsmartcapwap_usermodeid = 0;
if (sc_netlink_usermodeid == netlink_notify_portid(notify)) {
sc_netlink_usermodeid = 0;
/* Close all devices */
nlsmartcapwap_close();
sc_netlink_unregister_alldevice();
/* Close capwap engine */
sc_capwap_close();
/* Allow unload module */
module_put(THIS_MODULE);
}
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) {
u32 ifindex;
struct nlsmartcapwap_device* nldev;
int ret = -EINVAL;
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 != 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 */
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;
}
/* Check */
if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
return -EINVAL;
}
/* 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) {
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]);
}
/* */
if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) {
nldev->usermodeid = genl_info_snd_portid(info);
}
/* Connect device to mac80211 */
ret = ieee80211_pcktunnel_register(ifindex, &nldev->pcktunnel_handler);
ret = ieee80211_pcktunnel_register(nldev->dev, &nldev->pcktunnel_handler);
if (ret) {
nlsmartcapwap_unregister_device(ifindex);
sc_netlink_unregister_device(ifindex);
}
return ret;
}
/* */
static int nlsmartcapwap_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex;
static int sc_netlink_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_leave_mac80211_device\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
return -EINVAL;
}
ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]);
if (!ifindex) {
return -EINVAL;
}
/* 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_RADIOID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_CTRL_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_8023_FRAME] = { .type = NLA_FLAG },
[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_RX_RATE] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[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 */
static __genl_const struct genl_ops nlsmartcapwap_ops[] = {
static __genl_const struct genl_ops sc_netlink_ops[] = {
{
.cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = nlsmartcapwap_link,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_link,
.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,
},
{
.cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
.doit = nlsmartcapwap_join_mac80211_device,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_join_mac80211_device,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
.doit = nlsmartcapwap_leave_mac80211_device,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_leave_mac80211_device,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
};
/* Netlink notify */
static struct notifier_block nlsmartcapwap_netlink_notifier = {
.notifier_call = nlsmartcapwap_netlink_notify,
static struct notifier_block sc_netlink_notifier = {
.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;
/* Register netlink family */
ret = genl_register_family_with_ops(&nlsmartcapwap_family, nlsmartcapwap_ops);
TRACEKMOD("### sc_netlink_init\n");
/* */
sc_netlink_usermodeid = 0;
/* Register interface event */
ret = register_netdevice_notifier(&sc_device_notifier);
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 */
ret = netlink_register_notifier(&nlsmartcapwap_netlink_notifier);
ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) {
genl_unregister_family(&nlsmartcapwap_family);
return ret;
goto error3;
}
return 0;
error3:
genl_unregister_family(&sc_netlink_family);
error2:
unregister_netdevice_notifier(&sc_device_notifier);
error:
return ret;
}
/* */
void nlsmartcapwap_exit(void) {
/* */
rtnl_lock();
nlsmartcapwap_close();
rtnl_unlock();
void sc_netlink_exit(void) {
TRACEKMOD("### sc_netlink_exit\n");
/* */
netlink_unregister_notifier(&nlsmartcapwap_netlink_notifier);
genl_unregister_family(&nlsmartcapwap_family);
netlink_unregister_notifier(&sc_netlink_notifier);
genl_unregister_family(&sc_netlink_family);
unregister_netdevice_notifier(&sc_device_notifier);
}

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_CAPWAP_NETLINKAPP_HEADER__
#define __KMOD_CAPWAP_NETLINKAPP_HEADER__
#ifndef __KMOD_WTP_NETLINKAPP_HEADER__
#define __KMOD_WTP_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
int nlsmartcapwap_init(void);
void nlsmartcapwap_exit(void);
int sc_netlink_init(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__
#define __CAPWAP_NLSMARTCAPWAP_HEADER__
#ifndef __WTP_NLSMARTCAPWAP_HEADER__
#define __WTP_NLSMARTCAPWAP_HEADER__
/* */
#define SMARTCAPWAP_GENL_NAME "smartcapwap"
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp"
/* */
#define SMARTCAPWAP_FLAGS_SEND_USERSPACE 0x00000001
#define SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME 0x00000002
#define SMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000004
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
/* */
enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_IFINDEX,
NLSMARTCAPWAP_ATTR_RADIOID,
NLSMARTCAPWAP_ATTR_WLANID,
NLSMARTCAPWAP_ATTR_BINDING,
NLSMARTCAPWAP_ATTR_FLAGS,
@ -21,10 +22,17 @@ enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_FRAME,
NLSMARTCAPWAP_ATTR_8023_FRAME,
NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM,
NLSMARTCAPWAP_ATTR_RX_RATE,
NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_DTLS,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_RSSI,
NLSMARTCAPWAP_ATTR_SNR,
NLSMARTCAPWAP_ATTR_RATE,
/* Last attribute */
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
@ -37,14 +45,15 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_SET_AC_ADDRESS,
NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_CONNECT,
NLSMARTCAPWAP_CMD_TEARDOWN,
NLSMARTCAPWAP_CMD_RESET,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_FRAME,
NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
@ -54,4 +63,4 @@ enum nlsmartcapwap_commands {
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.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE;
/* DTLS */
g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
@ -76,8 +75,8 @@ static int wtp_init(void) {
/* AC information */
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN;
g_wtp.acdiscoveryrequest = 1;
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(struct sockaddr_storage), 0, 0);
g_wtp.acpreferedarray = 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(union sockaddr_capwap), 0, 0);
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1);
/* Radios */
@ -135,48 +134,22 @@ static void wtp_destroy(void) {
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() {
struct sockaddr_storage address;
struct sockaddr_in* addressv4 = (struct sockaddr_in*)&address;
/*struct sockaddr_in6* addressv6 = (struct sockaddr_in6*)&address;*/
static void wtp_add_default_acaddress() {
union sockaddr_capwap address;
/* Broadcast IPv4 */
addressv4->sin_family = AF_INET;
addressv4->sin_addr.s_addr = INADDR_BROADCAST;
addressv4->sin_port = htons(CAPWAP_CONTROL_PORT);
wtp_add_acaddress(&address, g_wtp.acdiscoveryarray);
memset(&address, 0, sizeof(union sockaddr_capwap));
address.sin.sin_family = AF_INET;
address.sin.sin_addr.s_addr = INADDR_BROADCAST;
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 */
/* TODO */
/* Multicast IPv6 */
/* TODO */
return ((g_wtp.acdiscoveryarray->count > 0) ? 1 : 0);
}
/* 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) {
int i;
int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
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;
}
}
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 */
@ -1094,7 +1052,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
return 0;
}
strcpy(g_wtp.net.bind_interface, configString);
strcpy(g_wtp.net.bindiface, configString);
}
/* 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 */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
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 */
if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) {
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");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct sockaddr_storage acaddr;
union sockaddr_capwap acaddr;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
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;
} else {
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");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct sockaddr_storage acaddr;
union sockaddr_capwap acaddr;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
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 {
capwap_logging_error("Invalid configuration file, invalid application.acprefered.host value");
return 0;
@ -1294,17 +1213,25 @@ static int wtp_load_configuration(int argc, char **argv) {
/* Init WTP */
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 (!g_wtp.acdiscoveryarray->count) {
if (!wtp_add_default_acaddress()) {
capwap_logging_debug("Unable add default AC discovery");
return WTP_ERROR_NETWORK;
}
wtp_add_default_acaddress();
}
/* Bind to any address */
if (!capwap_bind_sockets(&g_wtp.net)) {
capwap_logging_fatal("Cannot bind address");
/* Bind control address */
if (capwap_bind_sockets(&g_wtp.net)) {
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;
}
@ -1396,11 +1323,8 @@ int main(int argc, char** argv) {
wtp_wait_radio_ready();
/* Connect WTP with kernel module */
value = wtp_kmod_init();
if (!value || !g_wtp.kmodrequest) {
if (wtp_kmod_isconnected()) {
capwap_logging_info("SmartCAPWAP kernel module connected");
}
if (!wtp_kmod_init()) {
capwap_logging_info("SmartCAPWAP kernel module connected");
/* */
capwap_logging_info("Startup WTP");
@ -1411,7 +1335,7 @@ int main(int argc, char** argv) {
/* Running WTP */
result = wtp_dfa_running();
/* Close socket */
/* Close sockets */
capwap_close_sockets(&g_wtp.net);
}

View File

@ -68,13 +68,13 @@ struct wtp_t {
int running;
/* */
int kmodrequest;
struct wtp_kmod_handle kmodhandle;
/* */
char wlanprefix[IFNAMSIZ];
/* */
unsigned short mtu;
struct capwap_network net;
struct wtp_fds fds;
@ -113,21 +113,20 @@ struct wtp_t {
struct capwap_statisticstimer_element statisticstimer;
struct capwap_wtprebootstat_element rebootstat;
int tunneldataframe;
struct capwap_packet_rxmng* rxmngctrlpacket;
struct capwap_packet_rxmng* rxmngdatapacket;
/* */
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;
/* */
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short mtu;
unsigned short fragmentid;
uint8_t localseqnumber;
struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount;
/* */
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
/* */
int acdiscoveryrequest;
unsigned long acpreferedselected;
@ -135,13 +134,6 @@ struct wtp_t {
struct capwap_array* acpreferedarray;
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;
@ -154,8 +146,7 @@ struct wtp_t {
unsigned char dtlsdatapolicy;
unsigned char validdtlsdatapolicy;
struct capwap_dtls_context dtlscontext;
struct capwap_dtls ctrldtls;
struct capwap_dtls datadtls;
struct capwap_dtls dtls;
int faileddtlssessioncount;
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) {
struct capwap_packet_rxmng* rxmngpacket = NULL;
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;
static struct capwap_packet_rxmng* wtp_get_packet_rxmng(void) {
if (!g_wtp.rxmngpacket) {
g_wtp.rxmngpacket = capwap_packet_rxmng_create_message();
}
return rxmngpacket;
return g_wtp.rxmngpacket;
}
/* */
void wtp_free_packet_rxmng(int isctrlmsg) {
if (isctrlmsg && g_wtp.rxmngctrlpacket) {
capwap_packet_rxmng_free(g_wtp.rxmngctrlpacket);
g_wtp.rxmngctrlpacket = NULL;
} else if (!isctrlmsg && g_wtp.rxmngdatapacket) {
capwap_packet_rxmng_free(g_wtp.rxmngdatapacket);
g_wtp.rxmngdatapacket = NULL;
void wtp_free_packet_rxmng(void) {
if (g_wtp.rxmngpacket) {
capwap_packet_rxmng_free(g_wtp.rxmngpacket);
g_wtp.rxmngpacket = 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_packet_txmng* txmngpacket;
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->fragmentlist->first != NULL);
ASSERT(connection != NULL);
/* */
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);
/* 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 */
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;
ASSERT(fds != NULL);
@ -185,7 +169,7 @@ static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct soc
}
/* 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;
}
@ -335,13 +319,11 @@ int wtp_dfa_running(void) {
char* buffer;
int buffersize;
struct capwap_socket socket;
struct capwap_connection connection;
struct capwap_parsed_packet packet;
int index;
struct sockaddr_storage recvfromaddr;
struct sockaddr_storage recvtoaddr;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
/* Init */
memset(&packet, 0, sizeof(struct capwap_parsed_packet));
@ -366,79 +348,51 @@ int wtp_dfa_running(void) {
/* If request wait packet from AC */
buffer = bufferencrypt;
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) {
capwap_logging_debug("Closing WTP, Teardown connection");
wtp_dfa_closeapp();
break;
} else if (index >= 0) {
if (g_wtp.teardown) {
/* Drop packet */
continue;
continue; /* Drop packet */
} else {
int check;
/* Retrieve network information */
capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds.fdspoll[index].fd);
/* Check source */
if (socket.isctrlsocket && (g_wtp.acctrladdress.ss_family != AF_UNSPEC)) {
if (capwap_compare_ip(&g_wtp.acctrladdress, &recvfromaddr)) {
/* 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;
}
if (capwap_compare_ip(&g_wtp.dtls.peeraddr, &fromaddr)) {
continue; /* Unknown source */
}
/* 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) {
struct capwap_dtls* dtls = (socket.isctrlsocket ? &g_wtp.ctrldtls : &g_wtp.datadtls);
int oldaction = g_wtp.dtls.action;
if (dtls->enable) {
int oldaction = dtls->action;
/* Decrypt packet */
buffersize = capwap_decrypt_packet(dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
buffer = bufferplain;
check = CAPWAP_PLAIN_PACKET;
} else if (buffersize == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) {
if (socket.isctrlsocket) {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
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)) {
/* Decrypt packet */
buffersize = capwap_decrypt_packet(&g_wtp.dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
buffer = bufferplain;
check = CAPWAP_PLAIN_PACKET;
} else if (buffersize == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (g_wtp.dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
check = CAPWAP_NONE_PACKET;
wtp_send_join();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
continue; /* Next packet */
}
continue; /* Next packet */
} 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) {
capwap_logging_debug("Warning: sanity check failure");
@ -450,30 +404,8 @@ int wtp_dfa_running(void) {
if (check == CAPWAP_PLAIN_PACKET) {
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 */
rxmngpacket = wtp_get_packet_rxmng(socket.isctrlsocket);
rxmngpacket = wtp_get_packet_rxmng();
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, buffersize);
@ -481,63 +413,61 @@ int wtp_dfa_running(void) {
continue;
} else if (check != CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Discard fragments */
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
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 */
if (socket.isctrlsocket) {
if (capwap_recv_retrasmitted_request(&g_wtp.ctrldtls, rxmngpacket, &connection, g_wtp.lastrecvpackethash, g_wtp.responsefragmentpacket)) {
wtp_free_packet_rxmng(socket.isctrlsocket);
capwap_logging_debug("Retrasmitted packet");
continue;
if (capwap_is_request_type(rxmngpacket->ctrlmsg.type) && (g_wtp.remotetype == rxmngpacket->ctrlmsg.type) && (g_wtp.remoteseqnumber == rxmngpacket->ctrlmsg.seq)) {
/* Retransmit response */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_error("Error to resend response packet");
} else {
capwap_logging_debug("Retrasmitted control packet");
}
/* Check message type */
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);
}
continue;
}
capwap_logging_debug("Invalid message type");
wtp_free_packet_rxmng(socket.isctrlsocket);
continue;
/* Check message type */
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, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
}
capwap_logging_debug("Invalid message type");
wtp_free_packet_rxmng();
continue;
}
/* Parsing packet */
res = capwap_parsing_packet(rxmngpacket, &connection, &packet);
res = capwap_parsing_packet(rxmngpacket, &packet);
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");
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 */
}
/* */
capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
capwap_logging_debug("Failed parsing packet");
continue;
}
/* Validate packet */
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");
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);
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
capwap_logging_debug("Failed validation parsed packet");
continue;
}
@ -547,7 +477,7 @@ int wtp_dfa_running(void) {
/* Free 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)) {
@ -580,24 +510,32 @@ void wtp_free_reference_last_request(void) {
/* */
void wtp_free_reference_last_response(void) {
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) {
g_wtp.retransmitcount++;
if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) {
/* Timeout state */
wtp_free_reference_last_request();
if (!g_wtp.requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet");
wtp_teardown_connection();
} else {
/* Retransmit request */
capwap_logging_debug("Retransmition request packet");
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_error("Error to send request packet");
}
g_wtp.retransmitcount++;
if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) {
capwap_logging_info("Retransmition request packet timeout");
/* Update timeout */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
/* Timeout state */
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);
/* */
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param);
/* */
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_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);
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__ */

View File

@ -10,6 +10,7 @@
void wtp_send_configure(void) {
int i;
struct capwap_header_data capwapheader;
struct capwap_acnamepriority_element acnamepriority;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
@ -21,8 +22,12 @@ void wtp_send_configure(void) {
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_WTPREBOOTSTAT, &g_wtp.rebootstat);
/* CAPWAP_ELEMENT_ACNAMEPRIORITY */ /* TODO */
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 */
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
@ -86,7 +91,7 @@ void wtp_send_configure(void) {
capwap_packet_txmng_free(txmngpacket);
/* 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;
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);
@ -106,7 +111,7 @@ void wtp_dfa_state_configure(struct capwap_parsed_packet* packet) {
/* */
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 */
wtp_free_reference_last_request();

View File

@ -32,7 +32,7 @@ void wtp_send_datacheck(void) {
capwap_packet_txmng_free(txmngpacket);
/* 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;
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);
@ -51,7 +51,7 @@ void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet) {
/* */
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 */
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 countwtp = -1;
int indexpreferred = -1;
struct sockaddr_storage checkaddr;
struct sockaddr_in* checkaddripv4;
struct sockaddr_in6* checkaddripv6;
union sockaddr_capwap checkaddr;
union sockaddr_capwap peeraddr;
/* */
g_wtp.acctrladdress.ss_family = AF_UNSPEC;
peeraddr.ss.ss_family = AF_UNSPEC;
/* Selected by preferred or less WTP by AC */
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);
/* 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++) {
struct capwap_controlipv4_element* controlipv4 = (struct capwap_controlipv4_element*)capwap_array_get_item_pointer(response->controlipv4, 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);
/* Create IPv4 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage));
checkaddripv4 = (struct sockaddr_in*)&checkaddr;
checkaddripv4->sin_family = AF_INET;
checkaddripv4->sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv4->sin_addr, &controlipv4->address, sizeof(struct in_addr));
/* Create IPv4 address */
checkaddr.sin.sin_family = AF_INET;
memcpy(&checkaddr.sin.sin_addr, &controlipv4->address, sizeof(struct in_addr));
checkaddr.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
/* Check for preferred AC */
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);
/* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
union sockaddr_capwap* acpreferredaddr = (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
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;
}
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j;
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
break;
}
}
/* Check by number of WTP */
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
countwtp = controlipv4->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
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));
}
/* Check by number of WTP */
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
countwtp = controlipv4->wtpcount;
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
}
}
}
/* 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++) {
struct capwap_controlipv6_element* controlipv6 = (struct capwap_controlipv6_element*)capwap_array_get_item_pointer(response->controlipv6, w);
/* Create IPv6 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage));
checkaddripv6 = (struct sockaddr_in6*)&checkaddr;
checkaddripv6->sin6_family = AF_INET6;
checkaddripv6->sin6_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv6->sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
checkaddr.sin6.sin6_family = AF_INET6;
memcpy(&checkaddr.sin6.sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
checkaddr.sin6.sin6_port = htons(CAPWAP_CONTROL_PORT);
/* Check for preferred AC */
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)) {
indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
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));
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
break;
}
}
@ -106,9 +92,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv6->wtpcount)) {
countwtp = controlipv6->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
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));
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
}
}
}
@ -119,32 +103,24 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
wtp_free_discovery_response_array();
/* Change state if found AC */
if (g_wtp.acctrladdress.ss_family != AF_UNSPEC) {
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);
if (peeraddr.ss.ss_family != AF_UNSPEC) {
union sockaddr_capwap localaddr;
/* 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))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */
capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
/* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
}
}
}
@ -193,15 +169,8 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
/* Send discovery request to AC */
for (i = 0; i < g_wtp.acdiscoveryarray->count; i++) {
int sock;
struct sockaddr_storage* sendtoaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i);
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;
}
if (!capwap_sendto_fragmentpacket(g_wtp.net.socket, g_wtp.requestfragmentpacket, (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i))) {
capwap_logging_debug("Warning: error to send discovery request packet");
}
}
@ -223,7 +192,7 @@ void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) {
/* */
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;
/* 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();
}
/* 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) {
/* 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);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} 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);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} else {
@ -35,77 +26,34 @@ void wtp_start_dtlssetup(void) {
/* */
void wtp_start_datachannel(void) {
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
union sockaddr_capwap dataaddr;
/* If need, create DTLS Data channel crypted */
if (g_wtp.dtlsdatapolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) {
if (!g_wtp.datadtls.enable) {
/* 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();
}
/* Set AC data address */
memcpy(&dataaddr, &g_wtp.dtls.peeraddr, sizeof(union sockaddr_capwap));
CAPWAP_SET_NETWORK_PORT(&dataaddr, (CAPWAP_GET_NETWORK_PORT(&g_wtp.dtls.peeraddr) + 1));
return;
} else if (g_wtp.datadtls.action != CAPWAP_DTLS_ACTION_DATA) {
wtp_teardown_connection();
return;
}
}
/* Connect to AC data channel */
if (!wtp_kmod_connect(&dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu)) {
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;
/* 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)) {
/* 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();
}
/* 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 {
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();
}
/* 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) {
/* Free and reset resource */
if (g_wtp.ctrldtls.enable) {
capwap_crypt_freesession(&g_wtp.ctrldtls);
}
if (g_wtp.datadtls.enable) {
capwap_crypt_freesession(&g_wtp.datadtls);
if (g_wtp.dtls.enable) {
capwap_crypt_freesession(&g_wtp.dtls);
}
/* */
@ -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_response();
wtp_free_packet_rxmng(0);
wtp_free_packet_rxmng(1);
wtp_free_packet_rxmng();
/* */
if (!g_wtp.running) {
@ -140,15 +87,15 @@ void wtp_dfa_state_dtlsteardown(struct capwap_parsed_packet* packet) {
void wtp_teardown_connection(void) {
g_wtp.teardown = 1;
/* TODO: close SSID ? */
/* DTSL Control */
if (g_wtp.ctrldtls.enable) {
capwap_crypt_close(&g_wtp.ctrldtls);
if (g_wtp.dtls.enable) {
capwap_crypt_close(&g_wtp.dtls);
}
/* DTLS Data */
if (g_wtp.datadtls.enable) {
capwap_crypt_close(&g_wtp.datadtls);
}
/* Close data channel session */
wtp_kmod_resetsession();
/* */
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)) {
while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) {
union sockaddr_capwap localaddr;
union sockaddr_capwap peeraddr;
/* 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(&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);
memcpy(&peeraddr, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(union sockaddr_capwap));
/* Next AC */
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 */
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))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */
capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
/* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
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);
if (g_wtp.wtpctrladdress.ss_family == AF_INET) {
if (g_wtp.dtls.localaddr.ss.ss_family == AF_INET) {
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);
} 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;
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);
}
@ -76,7 +76,7 @@ void wtp_send_join(void) {
capwap_packet_txmng_free(txmngpacket);
/* 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;
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);
@ -97,7 +97,7 @@ void wtp_dfa_state_join(struct capwap_parsed_packet* packet) {
/* */
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 */
wtp_free_reference_last_request();

View File

@ -5,10 +5,6 @@
#include "wtp_radio.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) {
int result = -1;
@ -33,7 +29,7 @@ static int send_echo_request(void) {
capwap_packet_txmng_free(txmngpacket);
/* 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;
} else {
/* Error to send packets */
@ -94,11 +90,11 @@ static void receive_reset_request(struct capwap_parsed_packet* packet) {
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* 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");
}
}
@ -143,11 +139,11 @@ static void receive_station_configuration_request(struct capwap_parsed_packet* p
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* 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");
}
}
@ -203,213 +199,133 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
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 */
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");
}
}
}
/* */
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) {
capwap_logging_debug("Send Echo Request");
if (!send_echo_request()) {
g_wtp.retransmitcount = 0;
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
} else {
capwap_logging_error("Unable to send Echo Request");
wtp_teardown_connection();
}
}
/* */
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) {
capwap_logging_info("Keep-Alive timeout, teardown");
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) {
ASSERT(packet != NULL);
if (packet->rxmngpacket->isctrlpacket) {
if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
/* TODO */
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;
}
if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
/* TODO */
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