From 8d9985fdea55537f445bd577128e766d05daec0a Mon Sep 17 00:00:00 2001 From: vemax78 Date: Wed, 10 Sep 2014 21:58:23 +0200 Subject: [PATCH] The capwap data channel migrated from userspace to kernalspace --- AUTHORS | 0 ChangeLog | 0 LICENSING | 40 +- Makefile.am | 24 +- NEWS | 0 README | 0 build/Makefile.am | 61 +- build/Makefile_common.am | 216 ++-- build/ac/Makefile.am | 186 ++- build/wtp/Makefile.am | 145 ++- conf/ac.conf | 7 +- conf/wtp.conf | 10 +- configure.ac | 35 +- openwrt/Makefile | 4 +- .../920-mac80211_packet_tunnel.patch | 100 +- src/ac/ac.c | 78 +- src/ac/ac.h | 11 +- src/ac/ac_80211_json.c | 2 +- src/ac/ac_80211_json_antenna.c | 6 +- src/ac/ac_80211_json_directsequencecontrol.c | 6 +- src/ac/ac_80211_json_macoperation.c | 12 +- src/ac/ac_80211_json_multidomaincapability.c | 6 +- src/ac/ac_80211_json_ofdmcontrol.c | 6 +- src/ac/ac_80211_json_txpower.c | 2 +- src/ac/ac_80211_json_wtpradioconf.c | 12 +- src/ac/ac_80211_json_wtpradiofailalarm.c | 4 +- src/ac/ac_80211_json_wtpradioinformation.c | 2 +- src/ac/ac_backend.c | 36 +- src/ac/ac_dfa_configure.c | 78 +- src/ac/ac_dfa_datacheck.c | 26 +- src/ac/ac_dfa_dtls.c | 45 +- src/ac/ac_dfa_join.c | 55 +- src/ac/ac_dfa_run.c | 70 +- src/ac/ac_discovery.c | 24 +- src/ac/ac_discovery.h | 2 +- src/ac/ac_execute.c | 452 ++----- src/ac/ac_ieee80211_data.c | 77 +- src/ac/ac_kmod.c | 210 +++- src/ac/ac_kmod.h | 13 +- src/ac/ac_session.c | 243 ++-- src/ac/ac_session.h | 115 +- src/ac/ac_session_data.c | 527 -------- src/ac/ac_soap.c | 2 +- src/ac/ac_soap.h | 2 +- src/ac/ac_wlans.c | 9 +- src/ac/ac_wlans.h | 1 - src/ac/kmod/Makefile | 5 +- src/ac/kmod/capwap.c | 621 ++++++++++ src/ac/kmod/capwap.h | 128 ++ src/ac/kmod/capwap_private.c | 636 ++++++++++ src/ac/kmod/capwap_private.h | 26 + src/ac/kmod/capwap_rfc.h | 172 +++ src/ac/kmod/config.h | 13 + src/ac/kmod/main.c | 18 +- src/ac/kmod/netlinkapp.c | 451 +++++-- src/ac/kmod/netlinkapp.h | 11 +- src/ac/kmod/nlsmartcapwap.h | 49 +- src/ac/kmod/socket.c | 257 ++++ src/ac/kmod/socket.h | 45 + src/common/capwap_debug.c | 15 +- src/common/capwap_debug.h | 8 +- src/common/capwap_dtls.c | 78 +- src/common/capwap_dtls.h | 24 +- src/common/capwap_element.c | 888 ++++++-------- src/common/capwap_element.h | 5 +- src/common/capwap_network.c | 1088 ++++++----------- src/common/capwap_network.h | 89 +- src/common/capwap_protocol.c | 195 +-- src/common/capwap_protocol.h | 25 +- src/common/capwap_socket.c | 5 +- src/common/capwap_socket.h | 2 +- src/common/md5.c | 264 ---- src/common/md5.h | 53 - src/wtp/binding/ieee80211/wifi_drivers.c | 54 +- src/wtp/binding/ieee80211/wifi_drivers.h | 14 +- src/wtp/binding/ieee80211/wifi_nl80211.c | 24 +- src/wtp/kmod/Makefile | 5 +- src/wtp/kmod/capwap.c | 621 ++++++++++ src/wtp/kmod/capwap.h | 128 ++ src/wtp/kmod/capwap_private.c | 164 +++ src/wtp/kmod/capwap_private.h | 27 + src/wtp/kmod/capwap_rfc.h | 172 +++ src/wtp/kmod/config.h | 13 + src/wtp/kmod/main.c | 26 +- src/wtp/kmod/netlinkapp.c | 689 ++++++++--- src/wtp/kmod/netlinkapp.h | 17 +- src/wtp/kmod/nlsmartcapwap.h | 37 +- src/wtp/kmod/socket.c | 257 ++++ src/wtp/kmod/socket.h | 45 + src/wtp/wtp.c | 156 +-- src/wtp/wtp.h | 31 +- src/wtp/wtp_dfa.c | 238 ++-- src/wtp/wtp_dfa.h | 9 +- src/wtp/wtp_dfa_configure.c | 11 +- src/wtp/wtp_dfa_datacheck.c | 4 +- src/wtp/wtp_dfa_discovery.c | 121 +- src/wtp/wtp_dfa_dtls.c | 105 +- src/wtp/wtp_dfa_idle.c | 40 +- src/wtp/wtp_dfa_join.c | 12 +- src/wtp/wtp_dfa_run.c | 282 ++--- src/wtp/wtp_kmod.c | 298 +++-- src/wtp/wtp_kmod.h | 22 +- src/wtp/wtp_radio.c | 47 +- version.m4 | 5 - 104 files changed, 6967 insertions(+), 4840 deletions(-) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100644 NEWS create mode 100644 README delete mode 100644 src/ac/ac_session_data.c create mode 100644 src/ac/kmod/capwap.c create mode 100644 src/ac/kmod/capwap.h create mode 100644 src/ac/kmod/capwap_private.c create mode 100644 src/ac/kmod/capwap_private.h create mode 100644 src/ac/kmod/capwap_rfc.h create mode 100644 src/ac/kmod/config.h create mode 100644 src/ac/kmod/socket.c create mode 100644 src/ac/kmod/socket.h delete mode 100644 src/common/md5.c delete mode 100644 src/common/md5.h create mode 100644 src/wtp/kmod/capwap.c create mode 100644 src/wtp/kmod/capwap.h create mode 100644 src/wtp/kmod/capwap_private.c create mode 100644 src/wtp/kmod/capwap_private.h create mode 100644 src/wtp/kmod/capwap_rfc.h create mode 100644 src/wtp/kmod/config.h create mode 100644 src/wtp/kmod/socket.c create mode 100644 src/wtp/kmod/socket.h delete mode 100644 version.m4 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/LICENSING b/LICENSING index bc0e512..744ccbf 100644 --- a/LICENSING +++ b/LICENSING @@ -1,20 +1,20 @@ -SmartCAPWAP -- An Open Source CAPWAP WTP / AC - -Copyright (C) 2012-2013 Massimo Vellucci - - -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 + + +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. diff --git a/Makefile.am b/Makefile.am index 1ad0288..1acac3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/build/Makefile.am b/build/Makefile.am index d534fd1..1f216ff 100755 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -1,31 +1,30 @@ -# SmartCAPWAP -- An Open Source CAPWAP WTP / AC -# -# Copyright (C) 2012-2013 Massimo Vellucci -# -# 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 +# +# 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 diff --git a/build/Makefile_common.am b/build/Makefile_common.am index dec8bf3..3a81018 100755 --- a/build/Makefile_common.am +++ b/build/Makefile_common.am @@ -1,109 +1,107 @@ -# SmartCAPWAP -- An Open Source CAPWAP WTP / AC -# -# Copyright (C) 2012-2013 Massimo Vellucci -# -# 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 +# +# 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 diff --git a/build/ac/Makefile.am b/build/ac/Makefile.am index 5206bc3..d17239d 100755 --- a/build/ac/Makefile.am +++ b/build/ac/Makefile.am @@ -1,96 +1,90 @@ -# SmartCAPWAP -- An Open Source CAPWAP WTP / AC -# -# Copyright (C) 2012-2013 Massimo Vellucci -# -# 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 +# +# 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) diff --git a/build/wtp/Makefile.am b/build/wtp/Makefile.am index 9178a06..c61662f 100755 --- a/build/wtp/Makefile.am +++ b/build/wtp/Makefile.am @@ -1,75 +1,70 @@ -# SmartCAPWAP -- An Open Source CAPWAP WTP / AC -# -# Copyright (C) 2012-2013 Massimo Vellucci -# -# 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 +# +# 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 diff --git a/conf/ac.conf b/conf/ac.conf index 8dd2345..f0eaf38 100755 --- a/conf/ac.conf +++ b/conf/ac.conf @@ -66,12 +66,9 @@ application: { network: { #binding = "eth1"; - mtu = 1500; + #listen = ""; transport = "udp"; - - ipv4 = true; - ipv6 = false; - ipdualstack = true; + mtu = 1500; }; }; diff --git a/conf/wtp.conf b/conf/wtp.conf index f7df662..708fd46 100755 --- a/conf/wtp.conf +++ b/conf/wtp.conf @@ -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: { diff --git a/configure.ac b/configure.ac index 9ac234c..9948317 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ") 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)]) diff --git a/openwrt/Makefile b/openwrt/Makefile index 77a2019..c9907db 100644 --- a/openwrt/Makefile +++ b/openwrt/Makefile @@ -40,7 +40,7 @@ define KernelPackage/smartcapwap SUBMENU:=Network Support TITLE:=SmartCAPWAP Data Channel Module MAINTAINER:=Massimo Vellucci - 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 \ diff --git a/openwrt/mac80211_patchs/920-mac80211_packet_tunnel.patch b/openwrt/mac80211_patchs/920-mac80211_packet_tunnel.patch index 325aaa8..c6112dc 100644 --- a/openwrt/mac80211_patchs/920-mac80211_packet_tunnel.patch +++ b/openwrt/mac80211_patchs/920-mac80211_packet_tunnel.patch @@ -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); diff --git a/src/ac/ac.c b/src/ac/ac.c index f0cc24d..896d889 100644 --- a/src/ac/ac.c +++ b/src/ac/ac.c @@ -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 */ diff --git a/src/ac/ac.h b/src/ac/ac.h index 841e259..1bfd46c 100644 --- a/src/ac/ac.h +++ b/src/ac/ac.h @@ -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 */ diff --git a/src/ac/ac_80211_json.c b/src/ac/ac_80211_json.c index 39e0c80..2dbc846 100644 --- a/src/ac/ac_80211_json.c +++ b/src/ac/ac_80211_json.c @@ -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)) { diff --git a/src/ac/ac_80211_json_antenna.c b/src/ac/ac_80211_json_antenna.c index dcc2fe7..4e41c4c 100644 --- a/src/ac/ac_80211_json_antenna.c +++ b/src/ac/ac_80211_json_antenna.c @@ -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; diff --git a/src/ac/ac_80211_json_directsequencecontrol.c b/src/ac/ac_80211_json_directsequencecontrol.c index 9ad8c1e..e0da566 100644 --- a/src/ac/ac_80211_json_directsequencecontrol.c +++ b/src/ac/ac_80211_json_directsequencecontrol.c @@ -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 { diff --git a/src/ac/ac_80211_json_macoperation.c b/src/ac/ac_80211_json_macoperation.c index 0cdb7aa..2d58f6c 100644 --- a/src/ac/ac_80211_json_macoperation.c +++ b/src/ac/ac_80211_json_macoperation.c @@ -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 { diff --git a/src/ac/ac_80211_json_multidomaincapability.c b/src/ac/ac_80211_json_multidomaincapability.c index 837b169..641d505 100644 --- a/src/ac/ac_80211_json_multidomaincapability.c +++ b/src/ac/ac_80211_json_multidomaincapability.c @@ -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 { diff --git a/src/ac/ac_80211_json_ofdmcontrol.c b/src/ac/ac_80211_json_ofdmcontrol.c index 6d3a7d7..ebf81ad 100644 --- a/src/ac/ac_80211_json_ofdmcontrol.c +++ b/src/ac/ac_80211_json_ofdmcontrol.c @@ -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 { diff --git a/src/ac/ac_80211_json_txpower.c b/src/ac/ac_80211_json_txpower.c index 0307d9f..ebff98d 100644 --- a/src/ac/ac_80211_json_txpower.c +++ b/src/ac/ac_80211_json_txpower.c @@ -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 { diff --git a/src/ac/ac_80211_json_wtpradioconf.c b/src/ac/ac_80211_json_wtpradioconf.c index b119a0f..b242b39 100644 --- a/src/ac/ac_80211_json_wtpradioconf.c +++ b/src/ac/ac_80211_json_wtpradioconf.c @@ -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)) { diff --git a/src/ac/ac_80211_json_wtpradiofailalarm.c b/src/ac/ac_80211_json_wtpradiofailalarm.c index 0e1a2ba..c409cdd 100644 --- a/src/ac/ac_80211_json_wtpradiofailalarm.c +++ b/src/ac/ac_80211_json_wtpradiofailalarm.c @@ -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 { diff --git a/src/ac/ac_80211_json_wtpradioinformation.c b/src/ac/ac_80211_json_wtpradioinformation.c index 787f685..65c0daa 100644 --- a/src/ac/ac_80211_json_wtpradioinformation.c +++ b/src/ac/ac_80211_json_wtpradioinformation.c @@ -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 { diff --git a/src/ac/ac_backend.c b/src/ac/ac_backend.c index d5b1888..20427a7 100644 --- a/src/ac/ac_backend.c +++ b/src/ac/ac_backend.c @@ -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; diff --git a/src/ac/ac_dfa_configure.c b/src/ac/ac_dfa_configure.c index 3ae8006..18fda89 100644 --- a/src/ac/ac_dfa_configure.c +++ b/src/ac/ac_dfa_configure.c @@ -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); } diff --git a/src/ac/ac_dfa_datacheck.c b/src/ac/ac_dfa_datacheck.c index 16020a3..de3b220 100644 --- a/src/ac/ac_dfa_datacheck.c +++ b/src/ac/ac_dfa_datacheck.c @@ -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); -} diff --git a/src/ac/ac_dfa_dtls.c b/src/ac/ac_dfa_dtls.c index 0194287..0b3b7d3 100644 --- a/src/ac/ac_dfa_dtls.c +++ b/src/ac/ac_dfa_dtls.c @@ -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; } diff --git a/src/ac/ac_dfa_join.c b/src/ac/ac_dfa_join.c index 547c157..288ec12 100644 --- a/src/ac/ac_dfa_join.c +++ b/src/ac/ac_dfa_join.c @@ -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); } diff --git a/src/ac/ac_dfa_run.c b/src/ac/ac_dfa_run.c index 7ada3f0..39284b0 100644 --- a/src/ac/ac_dfa_run.c +++ b/src/ac/ac_dfa_run.c @@ -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(¬ify, 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*)¬ify, 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(¬ify, 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*)¬ify, 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 { diff --git a/src/ac/ac_discovery.c b/src/ac/ac_discovery.c index 9440a97..8878158 100644 --- a/src/ac/ac_discovery.c +++ b/src/ac/ac_discovery.c @@ -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"); } diff --git a/src/ac/ac_discovery.h b/src/ac/ac_discovery.h index c513341..a1f34db 100644 --- a/src/ac/ac_discovery.h +++ b/src/ac/ac_discovery.h @@ -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__ */ diff --git a/src/ac/ac_execute.c b/src/ac/ac_execute.c index f94e1a6..6ff7d42 100644 --- a/src/ac/ac_execute.c +++ b/src/ac/ac_execute.c @@ -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; } diff --git a/src/ac/ac_ieee80211_data.c b/src/ac/ac_ieee80211_data.c index e640398..92eac6d 100644 --- a/src/ac/ac_ieee80211_data.c +++ b/src/ac/ac_ieee80211_data.c @@ -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); } } diff --git a/src/ac/ac_kmod.c b/src/ac/ac_kmod.c index 86e7fb0..0a739fc 100644 --- a/src/ac/ac_kmod.c +++ b/src/ac/ac_kmod.c @@ -2,6 +2,7 @@ #include #include #include +#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; diff --git a/src/ac/ac_kmod.h b/src/ac/ac_kmod.h index 704e599..3f2994e 100644 --- a/src/ac/ac_kmod.h +++ b/src/ac/ac_kmod.h @@ -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__ */ diff --git a/src/ac/ac_session.c b/src/ac/ac_session.c index 0d462c6..b0a8d2b 100644 --- a/src/ac/ac_session.c +++ b/src/ac/ac_session.c @@ -6,8 +6,8 @@ #include "ac_backend.h" #include -#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); } diff --git a/src/ac/ac_session.h b/src/ac/ac_session.h index 2601b52..dc53adb 100644 --- a/src/ac/ac_session.h +++ b/src/ac/ac_session.h @@ -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 */ diff --git a/src/ac/ac_session_data.c b/src/ac/ac_session_data.c deleted file mode 100644 index 31c078a..0000000 --- a/src/ac/ac_session_data.c +++ /dev/null @@ -1,527 +0,0 @@ -#include "ac.h" -#include "capwap_dfa.h" -#include "ac_session.h" -#include "ac_wlans.h" -#include "ieee80211.h" -#include - -#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; -} diff --git a/src/ac/ac_soap.c b/src/ac/ac_soap.c index 25ce4f2..c2a38fc 100644 --- a/src/ac/ac_soap.c +++ b/src/ac/ac_soap.c @@ -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; diff --git a/src/ac/ac_soap.h b/src/ac/ac_soap.h index 2a1eb42..027c077 100644 --- a/src/ac/ac_soap.h +++ b/src/ac/ac_soap.h @@ -21,7 +21,7 @@ /* */ struct ac_http_soap_server { int protocol; - struct sockaddr_storage address; + union sockaddr_capwap address; char* host; char* path; diff --git a/src/ac/ac_wlans.c b/src/ac/ac_wlans.c index 492c8c1..3589122 100644 --- a/src/ac/ac_wlans.c +++ b/src/ac/ac_wlans.c @@ -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(¬ify, 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); } } } diff --git a/src/ac/ac_wlans.h b/src/ac/ac_wlans.h index 3340065..93802c0 100644 --- a/src/ac/ac_wlans.h +++ b/src/ac/ac_wlans.h @@ -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]; diff --git a/src/ac/kmod/Makefile b/src/ac/kmod/Makefile index 3fbd74b..0c5972f 100644 --- a/src/ac/kmod/Makefile +++ b/src/ac/kmod/Makefile @@ -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 diff --git a/src/ac/kmod/capwap.c b/src/ac/kmod/capwap.c new file mode 100644 index 0000000..c77f000 --- /dev/null +++ b/src/ac/kmod/capwap.c @@ -0,0 +1,621 @@ +#include "config.h" +#include +#include +#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; +} diff --git a/src/ac/kmod/capwap.h b/src/ac/kmod/capwap.h new file mode 100644 index 0000000..0738ecd --- /dev/null +++ b/src/ac/kmod/capwap.h @@ -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__ */ diff --git a/src/ac/kmod/capwap_private.c b/src/ac/kmod/capwap_private.c new file mode 100644 index 0000000..59f0204 --- /dev/null +++ b/src/ac/kmod/capwap_private.c @@ -0,0 +1,636 @@ +#include "config.h" +#include +#include +#include +#include +#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); +} diff --git a/src/ac/kmod/capwap_private.h b/src/ac/kmod/capwap_private.h new file mode 100644 index 0000000..d27268d --- /dev/null +++ b/src/ac/kmod/capwap_private.h @@ -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__ */ diff --git a/src/ac/kmod/capwap_rfc.h b/src/ac/kmod/capwap_rfc.h new file mode 100644 index 0000000..6fa149c --- /dev/null +++ b/src/ac/kmod/capwap_rfc.h @@ -0,0 +1,172 @@ +#ifndef __KMOD_CAPWAP_RFC_HEADER__ +#define __KMOD_CAPWAP_RFC_HEADER__ + +#include +#include + +/* */ +#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__ */ diff --git a/src/ac/kmod/config.h b/src/ac/kmod/config.h new file mode 100644 index 0000000..207855b --- /dev/null +++ b/src/ac/kmod/config.h @@ -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__ */ + diff --git a/src/ac/kmod/main.c b/src/ac/kmod/main.c index b086560..5c9661a 100644 --- a/src/ac/kmod/main.c +++ b/src/ac/kmod/main.c @@ -1,21 +1,29 @@ +#include "config.h" #include #include #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); diff --git a/src/ac/kmod/netlinkapp.c b/src/ac/kmod/netlinkapp.c index c8caa54..7634d13 100644 --- a/src/ac/kmod/netlinkapp.c +++ b/src/ac/kmod/netlinkapp.c @@ -1,5 +1,8 @@ +#include "config.h" #include #include +#include +#include #include #include #include @@ -9,90 +12,251 @@ #include #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); } diff --git a/src/ac/kmod/netlinkapp.h b/src/ac/kmod/netlinkapp.h index 8983134..8318ff8 100644 --- a/src/ac/kmod/netlinkapp.h +++ b/src/ac/kmod/netlinkapp.h @@ -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__ */ diff --git a/src/ac/kmod/nlsmartcapwap.h b/src/ac/kmod/nlsmartcapwap.h index ad74142..4b7bf31 100644 --- a/src/ac/kmod/nlsmartcapwap.h +++ b/src/ac/kmod/nlsmartcapwap.h @@ -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__ */ diff --git a/src/ac/kmod/socket.c b/src/ac/kmod/socket.c new file mode 100644 index 0000000..da45927 --- /dev/null +++ b/src/ac/kmod/socket.c @@ -0,0 +1,257 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; + } +} diff --git a/src/ac/kmod/socket.h b/src/ac/kmod/socket.h new file mode 100644 index 0000000..f8c2a9e --- /dev/null +++ b/src/ac/kmod/socket.h @@ -0,0 +1,45 @@ +#ifndef __KMOD_SOCKET_HEADER__ +#define __KMOD_SOCKET_HEADER__ + +#include +#include +#include +#include + +/* */ +#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__ */ diff --git a/src/common/capwap_debug.c b/src/common/capwap_debug.c index e0dcb98..4abc0d5 100644 --- a/src/common/capwap_debug.c +++ b/src/common/capwap_debug.c @@ -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; diff --git a/src/common/capwap_debug.h b/src/common/capwap_debug.h index 5124072..bac8e81 100644 --- a/src/common/capwap_debug.h +++ b/src/common/capwap_debug.h @@ -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 diff --git a/src/common/capwap_dtls.c b/src/common/capwap_dtls.c index c1bf088..39c34b3 100644 --- a/src/common/capwap_dtls.c +++ b/src/common/capwap_dtls.c @@ -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; diff --git a/src/common/capwap_dtls.h b/src/common/capwap_dtls.h index c2297b8..9c52528 100644 --- a/src/common/capwap_dtls.h +++ b/src/common/capwap_dtls.h @@ -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); diff --git a/src/common/capwap_element.c b/src/common/capwap_element.c index 59b3514..1de234c 100644 --- a/src/common/capwap_element.c +++ b/src/common/capwap_element.c @@ -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; } diff --git a/src/common/capwap_element.h b/src/common/capwap_element.h index 8c7a699..046a1a9 100644 --- a/src/common/capwap_element.h +++ b/src/common/capwap_element.h @@ -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__ */ diff --git a/src/common/capwap_network.c b/src/common/capwap_network.c index 77795a8..9a67fdb 100644 --- a/src/common/capwap_network.c +++ b/src/common/capwap_network.c @@ -1,98 +1,35 @@ #include "capwap.h" -#include "capwap_list.h" -#include "capwap_array.h" #include "capwap_network.h" #include "capwap_protocol.h" -#include -#include -#include -#include #include #include #include -#include #include -#define CAPWAP_ROUTE_NOT_FOUND 0 -#define CAPWAP_ROUTE_LOCAL_ADDRESS 1 -#define CAPWAP_ROUTE_VIA_ADDRESS 2 - -#ifndef IPV6_RECVPKTINFO -#define IPV6_RECVPKTINFO IPV6_PKTINFO -#endif +/* */ +#define CAPWAP_ROUTE_NOT_FOUND 0 +#define CAPWAP_ROUTE_LOCAL_ADDRESS 1 +#define CAPWAP_ROUTE_VIA_ADDRESS 2 /* Prepare socket to bind */ -static int capwap_configure_socket(int sock, int socketfamily, int socketprotocol, int usebroadcast, char* bindinterface, int flags) { +static int capwap_configure_socket(int sock, int socketfamily, const char* bindinterface) { int flag; ASSERT(sock >= 0); ASSERT((socketfamily == AF_INET) || (socketfamily == AF_INET6)); - ASSERT((socketprotocol == IPPROTO_UDP) || (socketprotocol == IPPROTO_UDPLITE)); - /* Set correct value for IPv6 if dualstack is disabled */ - if ((socketfamily == AF_INET6) && ((flags & CAPWAP_IPV6ONLY_FLAG) != 0)) { - int on = 1; - int result; - - usebroadcast = 0; - result = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof(int)); - if (result) { - capwap_logging_debug("Unable set IPV6_V6ONLY to socket"); - return -1; - } - } - - /* Reuse address */ - flag = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int))) { - capwap_logging_debug("Unable set SO_REUSEADDR to socket"); - return -1; - } - - /* Broadcast */ - if (usebroadcast) { - flag = 1; - if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(int))) { - capwap_logging_debug("Unable set SO_BROADCAST to socket"); - return -1; - } - } - - /* Bind to interface */ - if ((bindinterface != NULL) && (bindinterface[0] != 0)) { - if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, bindinterface, strlen(bindinterface) + 1)) { - capwap_logging_debug("Unable set SO_BINDTODEVICE to socket %d", errno); - return -1; - } - } - - /* Disable checksum */ - if (socketprotocol == IPPROTO_UDPLITE) { - flag = 8; - if (setsockopt(sock, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &flag, sizeof(int))) { - capwap_logging_debug("Unable set UDPLITE_SEND_CSCOV to socket"); - return -1; - } - } else if (socketfamily == AF_INET) { - flag = 1; - if (setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &flag, sizeof(int))) { - capwap_logging_debug("Unable set SO_NO_CHECK to socket"); - return -1; - } - } - - /* Retrieve information into sendto/recvfrom local address */ + /* Retrieve information into recvfrom local address */ if (socketfamily == AF_INET) { #ifdef IP_PKTINFO flag = 1; if (setsockopt(sock, SOL_IP, IP_PKTINFO, &flag, sizeof(int))) { - capwap_logging_debug("Unable set IP_PKTINFO to socket '%d'", errno); + capwap_logging_error("Unable set IP_PKTINFO to socket '%d'", errno); return -1; } #elif defined IP_RECVDSTADDR flag = 1; if (setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &flag, sizeof(int))) { - capwap_logging_debug("Unable set IP_RECVDSTADDR to socket '%d'", errno); + capwap_logging_error("Unable set IP_RECVDSTADDR to socket '%d'", errno); return -1; } #else @@ -101,7 +38,38 @@ static int capwap_configure_socket(int sock, int socketfamily, int socketprotoco } else if (socketfamily == AF_INET6) { flag = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &flag, sizeof(int))) { - capwap_logging_debug("Unable set IPV6_RECVPKTINFO to socket '%d'", errno); + capwap_logging_error("Unable set IPV6_RECVPKTINFO to socket '%d'", errno); + return -1; + } + } + + /* Reuse address */ + flag = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int))) { + capwap_logging_error("Unable set SO_REUSEADDR to socket"); + return -1; + } + + /* Broadcast */ + flag = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(int))) { + capwap_logging_error("Unable set SO_BROADCAST to socket"); + return -1; + } + + /* Bind to interface */ + if ((bindinterface != NULL) && (bindinterface[0] != 0)) { + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, bindinterface, strlen(bindinterface) + 1)) { + capwap_logging_error("Unable set SO_BINDTODEVICE to socket %d", errno); + return -1; + } + } + + /* Disable checksum */ + if (socketfamily == AF_INET) { + flag = 1; + if (setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &flag, sizeof(int))) { + capwap_logging_error("Unable set SO_NO_CHECK to socket"); return -1; } } @@ -109,203 +77,141 @@ static int capwap_configure_socket(int sock, int socketfamily, int socketprotoco return 0; } -/* */ -static void capwap_save_socket(struct capwap_network* net, int socketfamily, int socketprotocol, int sock_ctrl, int sock_data) { - int index; - - ASSERT(net != NULL); - ASSERT((socketfamily == AF_INET) || (socketfamily == AF_INET6)); - ASSERT((socketprotocol == IPPROTO_UDP) || (socketprotocol == IPPROTO_UDPLITE)); - ASSERT(sock_ctrl >= 0); - ASSERT(sock_data >= 0); - - if (socketfamily == AF_INET) { - if (socketprotocol == IPPROTO_UDP) { - index = CAPWAP_SOCKET_IPV4_UDP; - } else if (socketprotocol == IPPROTO_UDPLITE) { - index = CAPWAP_SOCKET_IPV4_UDPLITE; - } - } else if (socketfamily == AF_INET6) { - if (socketprotocol == IPPROTO_UDP) { - index = CAPWAP_SOCKET_IPV6_UDP; - } else if (socketprotocol == IPPROTO_UDPLITE) { - index = CAPWAP_SOCKET_IPV6_UDPLITE; - } - } - - net->sock_ctrl[index] = sock_ctrl; - net->sock_data[index] = sock_data; -} - /* Listen socket */ -static int capwap_prepare_bind_socket(struct capwap_network* net, int socketfamily, int socketprotocol) { - int result = 0; - int sock_ctrl = -1; - int sock_data = -1; - struct sockaddr_storage bindaddr; +static int capwap_prepare_bind_socket(struct capwap_network* net) { + int sock; ASSERT(net != NULL); - ASSERT((socketfamily == AF_INET) || (socketfamily == AF_INET6)); - ASSERT((socketprotocol == IPPROTO_UDP) || (socketprotocol == IPPROTO_UDPLITE)); - - /* */ - memset(&bindaddr, 0, sizeof(struct sockaddr_storage)); - bindaddr.ss_family = socketfamily; - if (socketfamily == AF_INET) { - ((struct sockaddr_in*)(&bindaddr))->sin_addr.s_addr = INADDR_ANY; - } else if (socketfamily == AF_INET6) { - memset(&((struct sockaddr_in6*)(&bindaddr))->sin6_addr, 0, sizeof(struct in6_addr)); + ASSERT((net->localaddr.ss.ss_family == AF_INET) || (net->localaddr.ss.ss_family == AF_INET6)); + + /* Create socket */ + sock = socket(net->localaddr.ss.ss_family, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + return -1; } - - /* Control socket */ - sock_ctrl = socket(socketfamily, SOCK_DGRAM, socketprotocol); - if (sock_ctrl >= 0) { - if (!capwap_configure_socket(sock_ctrl, socketfamily, socketprotocol, 1, net->bind_interface, net->bind_ctrl_flags)) { - /* Bind address */ - CAPWAP_SET_NETWORK_PORT(&bindaddr, net->bind_sock_ctrl_port); - if (!bind(sock_ctrl, (struct sockaddr*)&bindaddr, sizeof(struct sockaddr_storage))) { - /* Data socket */ - sock_data = socket(socketfamily, SOCK_DGRAM, socketprotocol); - if (sock_data >= 0) { - if (!capwap_configure_socket(sock_data, socketfamily, socketprotocol, 0, net->bind_interface, net->bind_data_flags)) { - /* Bind address */ - CAPWAP_SET_NETWORK_PORT(&bindaddr, (!net->bind_sock_ctrl_port ? 0 : net->bind_sock_ctrl_port + 1)); - if (!bind(sock_data, (struct sockaddr*)&bindaddr, sizeof(struct sockaddr_storage))) { - result = 1; - capwap_save_socket(net, socketfamily, socketprotocol, sock_ctrl, sock_data); - } else { - close(sock_data); - close(sock_ctrl); - } - } else { - close(sock_data); - close(sock_ctrl); - } - } else { - close(sock_ctrl); - } - } else { - close(sock_ctrl); - } - } else { - close(sock_ctrl); + + /* Prepare binding */ + if (capwap_configure_socket(sock, net->localaddr.ss.ss_family, net->bindiface)) { + close(sock); + return -1; + } + + /* Binding */ + if (bind(sock, &net->localaddr.sa, sizeof(union sockaddr_capwap))) { + close(sock); + return -1; + } + + /* Retrieve port */ + if (!CAPWAP_GET_NETWORK_PORT(&net->localaddr)) { + union sockaddr_capwap sockinfo; + socklen_t sockinfolen = sizeof(union sockaddr_capwap); + + if (getsockname(sock, &sockinfo.sa, &sockinfolen) < 0) { + close(sock); + return -1; } + + /* */ + CAPWAP_COPY_NETWORK_PORT(&net->localaddr, &sockinfo); } - - - return result; + + /* */ + net->socket = sock; + return 0; } /* */ int capwap_bind_sockets(struct capwap_network* net) { - int bindipv4 = 1; - - ASSERT(net != NULL); - - if ((net->sock_family == AF_UNSPEC) || (net->sock_family == AF_INET6)) { - /* UDP protocol */ - if (!capwap_prepare_bind_socket(net, AF_INET6, IPPROTO_UDP)) { - return 0; - } - - /* UDPLITE protocol */ - if (!capwap_prepare_bind_socket(net, AF_INET6, IPPROTO_UDPLITE)) { - return 0; - } - - /* Verify can use dual stack protocol */ - if ((net->bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) == 0) { - bindipv4 = 0; - } - } - - if (bindipv4 && ((net->sock_family == AF_UNSPEC) || (net->sock_family == AF_INET))) { - if (!capwap_prepare_bind_socket(net, AF_INET, IPPROTO_UDP)) { - return 0; - } - - if (!capwap_prepare_bind_socket(net, AF_INET, IPPROTO_UDPLITE)) { - return 0; - } - } - - return 1; -} - -/* Get socket */ -int capwap_get_socket(struct capwap_network* net, int socketfamily, int socketprotocol, int isctrlsocket) { - int index; + int result; ASSERT(net != NULL); - ASSERT((socketfamily == AF_INET) || (socketfamily == AF_INET6)); - ASSERT((socketprotocol == IPPROTO_UDP) || (socketprotocol == IPPROTO_UDPLITE)); - - if (socketfamily == AF_INET) { - if (socketprotocol == IPPROTO_UDP) { - index = CAPWAP_SOCKET_IPV4_UDP; - } else if (socketprotocol == IPPROTO_UDPLITE) { - index = CAPWAP_SOCKET_IPV4_UDPLITE; - } - } else if (socketfamily == AF_INET6) { - if (socketprotocol == IPPROTO_UDP) { - index = CAPWAP_SOCKET_IPV6_UDP; - } else if (socketprotocol == IPPROTO_UDPLITE) { - index = CAPWAP_SOCKET_IPV6_UDPLITE; - } + ASSERT((net->localaddr.ss.ss_family == AF_INET) || (net->localaddr.ss.ss_family == AF_INET6)); + + /* */ + result = capwap_prepare_bind_socket(net); + if (result && net->localaddr.ss.ss_family == AF_INET6) { + uint16_t port = net->localaddr.sin6.sin6_port; + + net->localaddr.ss.ss_family = AF_INET; + net->localaddr.sin.sin_port = port; + + result = capwap_prepare_bind_socket(net); } - return (isctrlsocket ? net->sock_ctrl[index] : net->sock_data[index]); + return result; } /* Close socket */ void capwap_close_sockets(struct capwap_network* net) { - int i; - ASSERT(net != NULL); - - for (i = 0; i < CAPWAP_MAX_SOCKETS; i++) { - if (net->sock_ctrl[i] >= 0) { - shutdown(net->sock_ctrl[i], SHUT_RDWR); - close(net->sock_ctrl[i]); - net->sock_ctrl[i] = -1; - } - - if (net->sock_data[i] >= 0) { - shutdown(net->sock_data[i], SHUT_RDWR); - close(net->sock_data[i]); - net->sock_data[i] = -1; - } + + if (net->socket >= 0) { + shutdown(net->socket, SHUT_RDWR); + close(net->socket); + net->socket = -1; } } +/* */ +int capwap_ipv4_mapped_ipv6(union sockaddr_capwap* addr) { + unsigned long inetaddr; + unsigned short inetport; + unsigned long* inet6addr; + + ASSERT(addr != NULL); + + /* */ + inet6addr = (unsigned long*)addr->sin6.sin6_addr.s6_addr; + if (addr->ss.ss_family == AF_INET) { + inetaddr = addr->sin.sin_addr.s_addr; + inetport = addr->sin.sin_port; + + /* Convert into IPv4 mapped IPv6 */ + addr->sin6.sin6_family = AF_INET; + inet6addr[0] = 0; + inet6addr[1] = 0; + inet6addr[2] = htonl(0xffff); + inet6addr[3] = inetaddr; + addr->sin6.sin6_port = inetport; + + return 1; + } else if ((addr->ss.ss_family == AF_INET6) && (IN6_IS_ADDR_V4MAPPED(&addr->sin6.sin6_addr))) { + inetaddr = inet6addr[3]; + inetport = addr->sin6.sin6_port; + + /* Convert into IPv4 */ + addr->sin.sin_family = AF_INET; + addr->sin.sin_addr.s_addr = inetaddr; + addr->sin.sin_port = inetport; + + return 1; + } + + return 0; +} + /* Compare ip address */ -int capwap_compare_ip(struct sockaddr_storage* addr1, struct sockaddr_storage* addr2) { +int capwap_compare_ip(union sockaddr_capwap* addr1, union sockaddr_capwap* addr2) { ASSERT(addr1 != NULL); ASSERT(addr2 != NULL); - if (addr1->ss_family == addr2->ss_family) { - if (addr1->ss_family == AF_INET) { - struct sockaddr_in* addr1_in = (struct sockaddr_in*)addr1; - struct sockaddr_in* addr2_in = (struct sockaddr_in*)addr2; - - if (addr1_in->sin_addr.s_addr == addr2_in->sin_addr.s_addr) { - if (addr1_in->sin_port == addr2_in->sin_port) { - return 0; - } - } - } else if (addr1->ss_family == AF_INET6) { - struct sockaddr_in6* addr1_in6 = (struct sockaddr_in6*)addr1; - struct sockaddr_in6* addr2_in6 = (struct sockaddr_in6*)addr2; + if (addr1->ss.ss_family != addr2->ss.ss_family) { + return -1; + } - if (!memcmp(&addr1_in6->sin6_addr, &addr2_in6->sin6_addr, sizeof(struct in6_addr))) { - if (addr1_in6->sin6_port == addr2_in6->sin6_port) { - return 0; - } - } + /* */ + if (addr1->ss.ss_family == AF_INET) { + if ((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) { + return 0; + } + } else if (addr1->ss.ss_family == AF_INET6) { + if (!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) { + return 0; } } - - return 1; + + return -1; } /* Wait receive packet with timeout */ @@ -335,9 +241,9 @@ int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeou if (readysocket > 0) { /* Get packet from only one socket */ for (i = 0; i < fdscount; i++) { - if ((fds[i].revents & POLLIN) != 0) { + if (fds[i].revents & POLLIN) { return i; - } else if ((fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) != 0) { + } else if ((fds[i].revents & (POLLHUP | POLLERR | POLLNVAL))) { return CAPWAP_RECV_ERROR_SOCKET; } } @@ -352,370 +258,139 @@ int capwap_wait_recvready(struct pollfd* fds, int fdscount, struct capwap_timeou } /* Receive packet from fd */ -int capwap_recvfrom_fd(int fd, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) { - int packetsize = -1; - socklen_t sendaddresslen = sizeof(struct sockaddr_storage); - struct sockaddr_storage sockinfo; - socklen_t sockinfolen = sizeof(struct sockaddr_storage); +int capwap_recvfrom(int sock, void* buffer, int* size, union sockaddr_capwap* fromaddr, union sockaddr_capwap* toaddr) { + int result = 0; struct iovec iov; struct msghdr msgh; struct cmsghdr* cmsg; char cbuf[256]; - ASSERT(fd >= 0); + ASSERT(sock >= 0); ASSERT(buffer != NULL); ASSERT(size != NULL); ASSERT(*size > 0); - ASSERT(recvfromaddr != NULL); - ASSERT(recvtoaddr != NULL); - - memset(recvfromaddr, 0, sizeof(struct sockaddr_storage)); - if (recvtoaddr) { - memset(recvtoaddr, 0, sizeof(struct sockaddr_storage)); - } - - /* Information socket */ - memset(&sockinfo, 0, sizeof(struct sockaddr_storage)); - if (getsockname(fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) { - return 0; - } + ASSERT(fromaddr != NULL); + /* */ iov.iov_base = buffer; iov.iov_len = *size; memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); - msgh.msg_name = recvfromaddr; - msgh.msg_namelen = sendaddresslen; + msgh.msg_name = &fromaddr->ss; + msgh.msg_namelen = sizeof(struct sockaddr_storage); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; /* Receive packet with recvmsg */ - do { - packetsize = recvmsg(fd, &msgh, 0); - } while ((packetsize < 0) && ((errno == EAGAIN) || (errno == EINTR))); + while (result <= 0) { + result = recvmsg(sock, &msgh, 0); + if ((result <= 0) && (errno != EAGAIN) && (errno != EINTR)) { + return -1; + } + } - if (packetsize > 0) { + /* Check if IPv4 is mapped into IPv6 */ + if (fromaddr->ss.ss_family == AF_INET6) { + capwap_ipv4_mapped_ipv6(fromaddr); + } + + /* */ + if (toaddr) { for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { #ifdef IP_PKTINFO if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { - struct in_pktinfo* i = (struct in_pktinfo*)CMSG_DATA(cmsg); - struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr; - - addr->sin_family = AF_INET; - memcpy(&addr->sin_addr, &i->ipi_addr, sizeof(struct in_addr)); - addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port; - + toaddr->sin.sin_family = AF_INET; + memcpy(&toaddr->sin.sin_addr, &((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_addr, sizeof(struct in_addr)); break; } #elif defined IP_RECVDSTADDR if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) { - struct in_addr* i = (struct in_addr*)CMSG_DATA(cmsg); - struct sockaddr_in* addr = (struct sockaddr_in*)recvtoaddr; - - addr->sin_family = AF_INET; - memcpy(&addr->sin_addr, i, sizeof(struct in_addr)); - addr->sin_port = ((struct sockaddr_in*)&sockinfo)->sin_port; - + toaddr->sin.sin_family = AF_INET; + memcpy(&toaddr->sin.sin_addr, (struct in_addr*)CMSG_DATA(cmsg), sizeof(struct in_addr)); break; } -#else - #error "No method of getting the destination ip address supported" #endif if ((cmsg->cmsg_level == IPPROTO_IPV6) && ((cmsg->cmsg_type == IPV6_PKTINFO) || (cmsg->cmsg_type == IPV6_RECVPKTINFO))) { - struct in6_pktinfo* i = (struct in6_pktinfo*)CMSG_DATA(cmsg); - struct sockaddr_in6* addr = (struct sockaddr_in6*)recvtoaddr; + toaddr->sin6.sin6_family = AF_INET6; + memcpy(&toaddr->sin6.sin6_addr, &((struct in6_pktinfo*)CMSG_DATA(cmsg))->ipi6_addr, sizeof(struct in6_addr)); - addr->sin6_family = AF_INET6; - memcpy(&addr->sin6_addr, &i->ipi6_addr, sizeof(struct in6_addr)); - addr->sin6_port = ((struct sockaddr_in6*)&sockinfo)->sin6_port; + /* Check if IPv4 is mapped into IPv6 */ + if (fromaddr->ss.ss_family == AF_INET) { + if (!capwap_ipv4_mapped_ipv6(toaddr)) { + return -1; + } + } break; } } - } else if (packetsize < 0) { - return 0; } /* Packet receive */ - *size = packetsize; - return 1; -} - -/* Receive packet with timeout */ -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 index; - - ASSERT(fds); - ASSERT(fdscount > 0); - ASSERT(buffer != NULL); - ASSERT(size != NULL); - ASSERT(*size > 0); - ASSERT(recvfromaddr != NULL); - ASSERT(recvtoaddr != NULL); - - /* Wait packet */ - index = capwap_wait_recvready(fds, fdscount, timeout); - if (index < 0) { - return index; - } - - /* Receive packet */ - if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) { - return CAPWAP_RECV_ERROR_SOCKET; - } - - return index; + *size = result; + return 0; } /* */ void capwap_network_init(struct capwap_network* net) { - int i; - ASSERT(net != NULL); /* */ memset(net, 0, sizeof(struct capwap_network)); /* */ - net->sock_family = AF_UNSPEC; - net->bind_sock_ctrl_port = INADDR_ANY; - for (i = 0; i < CAPWAP_MAX_SOCKETS; i++) { - net->sock_ctrl[i] = -1; - net->sock_data[i] = -1; - } + net->localaddr.ss.ss_family = AF_UNSPEC; + net->socket = -1; } /* */ int capwap_network_set_pollfd(struct capwap_network* net, struct pollfd* fds, int fdscount) { - int i; - int j; - int count = 0; - ASSERT(net != NULL); ASSERT(fdscount >= 0); /* */ - if (!fds && fdscount) { - return -1; - } - - /* Count the socket */ - for (i = 0; i < CAPWAP_MAX_SOCKETS; i++) { - if (net->sock_ctrl[i] >= 0) { - ASSERT(net->sock_data[i] >= 0); - count++; - } - } - - /* */ - if (!fds && !fdscount) { - return (count * 2); - } - - /* Check size of fds array */ - if (fdscount < (count * 2)) { + if (!fds) { + return (!fdscount ? 1 : -1); + } else if (fdscount < 1) { return -1; } /* Configure fds array */ - for (i = 0, j = 0; i < CAPWAP_MAX_SOCKETS; i++) { - if (net->sock_ctrl[i] >= 0) { - fds[j].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; - fds[j].fd = net->sock_ctrl[i]; - fds[j + count].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; - fds[j + count].fd = net->sock_data[i]; + fds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; + fds[0].fd = net->socket; - j++; - } - } - - return (count * 2); + return 1; } /* */ -void capwap_get_network_socket(struct capwap_network* net, struct capwap_socket* sock, int fd) { - int i; - - ASSERT(net != NULL); - ASSERT(sock != NULL); - ASSERT(fd >= 0); +int capwap_sendto(int sock, void* buffer, int size, union sockaddr_capwap* toaddr) { + int result = 0; - for (i = 0; i < CAPWAP_MAX_SOCKETS; i++) { - if (net->sock_ctrl[i] == fd) { - sock->isctrlsocket = 1; - switch (i) { - case CAPWAP_SOCKET_IPV4_UDP: { - sock->family = AF_INET; - sock->type = CAPWAP_SOCKET_UDP; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_ctrl[i]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_ctrl[i + 1]; - break; - } - - case CAPWAP_SOCKET_IPV4_UDPLITE: { - sock->family = AF_INET; - sock->type = CAPWAP_SOCKET_UDPLITE; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_ctrl[i - 1]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_ctrl[i]; - break; - } - - case CAPWAP_SOCKET_IPV6_UDP: { - sock->family = AF_INET6; - sock->type = CAPWAP_SOCKET_UDP; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_ctrl[i]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_ctrl[i + 1]; - break; - } - - case CAPWAP_SOCKET_IPV6_UDPLITE: { - sock->family = AF_INET6; - sock->type = CAPWAP_SOCKET_UDPLITE; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_ctrl[i - 1]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_ctrl[i]; - break; - } - } - - break; - } else if (net->sock_data[i] == fd) { - sock->isctrlsocket = 0; - switch (i) { - case CAPWAP_SOCKET_IPV4_UDP: { - sock->family = AF_INET; - sock->type = CAPWAP_SOCKET_UDP; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_data[i]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_data[i + 1]; - break; - } - - case CAPWAP_SOCKET_IPV4_UDPLITE: { - sock->family = AF_INET; - sock->type = CAPWAP_SOCKET_UDPLITE; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_data[i - 1]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_data[i]; - break; - } - - case CAPWAP_SOCKET_IPV6_UDP: { - sock->family = AF_INET6; - sock->type = CAPWAP_SOCKET_UDP; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_data[i]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_data[i + 1]; - break; - } - - case CAPWAP_SOCKET_IPV6_UDPLITE: { - sock->family = AF_INET6; - sock->type = CAPWAP_SOCKET_UDPLITE; - sock->socket[CAPWAP_SOCKET_UDP] = net->sock_data[i - 1]; - sock->socket[CAPWAP_SOCKET_UDPLITE] = net->sock_data[i]; - break; - } - } - - break; - } - } -} - -/* */ -int capwap_sendto(int sock, void* buffer, int size, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr) { - int result; - ASSERT(sock >= 0); ASSERT(buffer != NULL); ASSERT(size > 0); - ASSERT(sendtoaddr != NULL); - - /* Information socket */ - if (!sendfromaddr) { - do { - result = sendto(sock, buffer, size, 0, (struct sockaddr*)sendtoaddr, sizeof(struct sockaddr_storage)); - } while ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))); - } else { - struct msghdr msgh; - struct cmsghdr* cmsg; - struct iovec iov; - char cbuf[256]; - - /* */ - memset(&msgh, 0, sizeof(struct msghdr)); - iov.iov_base = buffer; - iov.iov_len = size; - msgh.msg_iov = &iov; - msgh.msg_iovlen = 1; - msgh.msg_name = sendtoaddr; - msgh.msg_namelen = sizeof(struct sockaddr_storage); + ASSERT(toaddr != NULL); - if (sendfromaddr->ss_family == AF_INET) { - struct sockaddr_in* addr = (struct sockaddr_in*)sendfromaddr; - -#ifdef IP_PKTINFO - struct in_pktinfo* pkt; - - msgh.msg_control = cbuf; - msgh.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&msgh); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - - pkt = (struct in_pktinfo*)CMSG_DATA(cmsg); - memset(pkt, 0, sizeof(struct in_pktinfo)); - memcpy(&pkt->ipi_spec_dst, &addr->sin_addr, sizeof(struct in_addr)); -#elif defined IP_RECVDSTADDR - struct in_addr* in; - - msgh.msg_control = cbuf; - msgh.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); - - cmsg = CMSG_FIRSTHDR(&msgh); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - - in = (struct in_addr*)CMSG_DATA(cmsg); - memcpy(in, &addr->sin_addr, sizeof(struct in_addr)); -#else - #error "No method of getting the destination ip address supported" -#endif - } else if (sendfromaddr->ss_family == AF_INET6) { - struct in6_pktinfo* pkt; - struct sockaddr_in6* addr = (struct sockaddr_in6*)sendfromaddr; - - msgh.msg_control = cbuf; - msgh.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - - cmsg = CMSG_FIRSTHDR(&msgh); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - - pkt = (struct in6_pktinfo*)CMSG_DATA(cmsg); - memset(pkt, 0, sizeof(struct in6_pktinfo)); - memcpy(&pkt->ipi6_addr, &addr->sin6_addr, sizeof(struct in6_addr)); + while (result <= 0) { + result = sendto(sock, buffer, size, 0, &toaddr->sa, sizeof(union sockaddr_capwap)); + if ((result <= 0) && (errno != EAGAIN) && (errno != EINTR)) { + return -1; } - - do { - result = sendmsg(sock, &msgh, 0); - } while ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))); } - return ((result > 0) ? size : 0); + return result; } /* */ -int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, struct sockaddr_storage* sendfromaddr, struct sockaddr_storage* sendtoaddr) { +int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, union sockaddr_capwap* toaddr) { struct capwap_list_item* item; ASSERT(sock >= 0); ASSERT(fragmentlist != NULL); - ASSERT(sendtoaddr != NULL); + ASSERT(toaddr != NULL); item = fragmentlist->first; while (item) { @@ -723,7 +398,7 @@ int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, str ASSERT(fragmentpacket != NULL); ASSERT(fragmentpacket->offset > 0); - if (!capwap_sendto(sock, fragmentpacket->buffer, fragmentpacket->offset, sendfromaddr, sendtoaddr)) { + if (!capwap_sendto(sock, fragmentpacket->buffer, fragmentpacket->offset, toaddr)) { return 0; } @@ -734,41 +409,8 @@ int capwap_sendto_fragmentpacket(int sock, struct capwap_list* fragmentlist, str return 1; } -/* */ -int capwap_ipv4_mapped_ipv6(struct sockaddr_storage* source, struct sockaddr_storage* dest) { - ASSERT(source != NULL); - ASSERT(dest != NULL); - - memset(dest, 0, sizeof(struct sockaddr_storage)); - - if (source->ss_family == AF_INET) { - struct sockaddr_in* addripv4 = (struct sockaddr_in*)source; - struct sockaddr_in6* addripv6 = (struct sockaddr_in6*)dest; - - addripv6->sin6_family = AF_INET6; - ((unsigned long*)&addripv6->sin6_addr)[2] = htonl(0xffff); - memcpy(&((unsigned long*)&addripv6->sin6_addr)[3], &addripv4->sin_addr, sizeof(unsigned long)); - addripv6->sin6_port = addripv4->sin_port; - - return 1; - } else if (source->ss_family == AF_INET6) { - struct sockaddr_in6* addripv6 = (struct sockaddr_in6*)source; - struct sockaddr_in* addripv4 = (struct sockaddr_in*)dest; - - if (IN6_IS_ADDR_V4MAPPED(&addripv6->sin6_addr)) { - addripv4->sin_family = AF_INET; - memcpy(&addripv4->sin_addr, &((unsigned long*)&addripv6->sin6_addr)[3], sizeof(unsigned long)); - addripv4->sin_port = addripv6->sin6_port; - - return 1; - } - } - - return 0; -} - /* Convert string into address */ -int capwap_address_from_string(const char* ip, struct sockaddr_storage* address) { +int capwap_address_from_string(const char* ip, union sockaddr_capwap* sockaddr) { char* pos; char* buffer; struct addrinfo hints; @@ -776,10 +418,10 @@ int capwap_address_from_string(const char* ip, struct sockaddr_storage* address) char* service = NULL; ASSERT(ip != NULL); - ASSERT(address != NULL); + ASSERT(sockaddr != NULL); /* Init */ - memset(address, 0, sizeof(struct sockaddr_storage)); + memset(sockaddr, 0, sizeof(union sockaddr_capwap)); if (!*ip) { return 0; } @@ -831,7 +473,7 @@ int capwap_address_from_string(const char* ip, struct sockaddr_storage* address) } /* Copy address */ - memcpy(address, info->ai_addr, info->ai_addrlen); + memcpy(&sockaddr->ss, info->ai_addr, info->ai_addrlen); freeaddrinfo(info); capwap_free(buffer); @@ -866,139 +508,105 @@ int capwap_get_macaddress_from_interface(const char* interface, char* macaddress } /* */ -static void capwap_get_network_address(struct sockaddr_storage* addr, struct sockaddr_storage* network, unsigned long bitsmask) { +static void capwap_get_network_address(union sockaddr_capwap* addr, union sockaddr_capwap* network, unsigned long bitsmask) { unsigned long i; - + ASSERT(addr != NULL); ASSERT(network != NULL); - memcpy(network, addr, sizeof(struct sockaddr_storage)); + memcpy(network, addr, sizeof(union sockaddr_capwap)); - if (addr->ss_family == AF_INET) { + if (addr->ss.ss_family == AF_INET) { unsigned long mask = 0xffffffff; - struct sockaddr_in* ipv4addr = (struct sockaddr_in*)network; for (i = bitsmask; i < 32; i++) { mask <<= 1; } - ipv4addr->sin_addr.s_addr &= htonl(mask); + network->sin.sin_addr.s_addr &= htonl(mask); } else { unsigned long pos = bitsmask / 8; unsigned long delta = bitsmask % 8; - struct sockaddr_in6* ipv6addr = (struct sockaddr_in6*)network; - + if (!delta) { - pos -= 1; /* Optimize for all bits of pos equal 0 */ + pos -= 1; /* Optimize for all bits of pos equal 0 */ } else { unsigned char mask = 0xff; for (i = delta; i < 8; i++) { mask <<= 1; } - - ipv6addr->sin6_addr.s6_addr[pos] &= mask; + + network->sin6.sin6_addr.s6_addr[pos] &= mask; } - + for (i = pos + 1; i < 16; i++) { - ipv6addr->sin6_addr.s6_addr[i] = 0; + network->sin6.sin6_addr.s6_addr[i] = 0; } } } /* */ -static int capwap_equal_address(struct sockaddr_storage* addr1, struct sockaddr_storage* addr2) { - ASSERT(addr1 != NULL); - ASSERT(addr2 != NULL); - - if (addr1->ss_family == addr2->ss_family) { - if (addr1->ss_family == AF_INET) { - if (((struct sockaddr_in*)addr1)->sin_addr.s_addr == ((struct sockaddr_in*)addr2)->sin_addr.s_addr) { - return 1; - } - } else if (addr1->ss_family == AF_INET6) { - int i; - struct in6_addr* ipv6addr1 = &((struct sockaddr_in6*)addr1)->sin6_addr; - struct in6_addr* ipv6addr2 = &((struct sockaddr_in6*)addr2)->sin6_addr; - - for (i = 0; i < 16; i++) { - if (ipv6addr1->s6_addr[i] != ipv6addr2->s6_addr[i]) { - return 0; - } - } - - return 1; - } - } - - return 0; -} +static int capwap_get_routeaddress(union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr, char* iface, unsigned char table) { + int result = CAPWAP_ROUTE_NOT_FOUND; -/* */ -static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockaddr_storage* remote, char* oif, int ipv6dualstack, unsigned char table) { - int result = 0; - int end = 0; - int foundgateway = 0; unsigned char gatewaytable = 0; unsigned long gatewaymetric = 0; - struct sockaddr_storage gateway; + union sockaddr_capwap gateway; int nlsock; struct sockaddr_nl nllocal; socklen_t nllocaladdrlen; int sndbuf = 32768; int rcvbuf = 32768; - + struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; - ASSERT(local != NULL); - ASSERT(remote != NULL); + ASSERT(localaddr != NULL); + ASSERT(peeraddr != NULL); + + /* */ + memset(localaddr, 0, sizeof(union sockaddr_capwap)); /* Open netlink route socket */ nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nlsock < 0) { - capwap_logging_debug("Cannot open netlink socket"); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } - /* Configure socket */ + /* Configure socket */ if (setsockopt(nlsock, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0) { - capwap_logging_debug("Cannot set SO_SNDBUF"); close(nlsock); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } if (setsockopt(nlsock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0) { - capwap_logging_debug("Cannot set SO_RCVBUF"); close(nlsock); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } - + /* Bind */ memset(&nllocal, 0, sizeof(struct sockaddr_nl)); nllocal.nl_family = AF_NETLINK; if (bind(nlsock, (struct sockaddr*)&nllocal, sizeof(struct sockaddr_nl)) < 0) { - capwap_logging_debug("Cannot bind netlink socket"); close(nlsock); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } /* Check bind */ nllocaladdrlen = sizeof(struct sockaddr_nl); if (getsockname(nlsock, (struct sockaddr*)&nllocal, &nllocaladdrlen) < 0) { - capwap_logging_debug("Cannot getsockname"); close(nlsock); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } if ((nllocaladdrlen != sizeof(struct sockaddr_nl)) || (nllocal.nl_family != AF_NETLINK)) { - capwap_logging_debug("Wrong bind netlink socket"); close(nlsock); - return 0; + return CAPWAP_ROUTE_NOT_FOUND; } /* Send request */ @@ -1009,8 +617,9 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = 0; req.g.rtgen_family = AF_UNSPEC; - + if (send(nlsock, (void*)&req, sizeof(req), 0) == sizeof(req)) { + int end = 0; struct sockaddr_nl nladdr; struct iovec iov; char buf[16384]; @@ -1020,26 +629,25 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad .msg_iov = &iov, .msg_iovlen = 1, }; - + iov.iov_base = buf; - while (!result && !end) { + while ((result == CAPWAP_ROUTE_NOT_FOUND) && !end) { int status; struct nlmsghdr *h; - + /* Receive response */ iov.iov_len = sizeof(buf); status = recvmsg(nlsock, &msg, 0); if (status < 0) { - if ((errno == EINTR) || (errno == EAGAIN)) + if ((errno == EINTR) || (errno == EAGAIN)) { continue; + } - capwap_logging_debug("Error from netlink socket: %d", errno); break; - } else if (status == 0) { - capwap_logging_debug("Receive EOF by netlink socket"); + } else if (!status) { break; } - + /* Parsing message */ h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { @@ -1052,12 +660,11 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); /* Accept only address IPv4 or IPv6 from main table route */ - if ((len >= 0) && (!table || (r->rtm_table == table)) && (remote->ss_family == r->rtm_family)) { + if ((len >= 0) && (!table || (r->rtm_table == table)) && (peeraddr->ss.ss_family == r->rtm_family)) { struct rtattr* tb[RTA_MAX + 1]; struct rtattr* rta = RTM_RTA(r); int addrsize = ((r->rtm_family == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr)); int defaultgateway = 0; - struct sockaddr_storage dest; int destmask = r->rtm_dst_len; char ifname[IFNAMSIZ + 1]; @@ -1070,7 +677,7 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad rta = RTA_NEXT(rta, len); } - + /* Get device name */ if (tb[RTA_OIF]) { if (!if_indextoname(*(int*)RTA_DATA(tb[RTA_OIF]), ifname)) { @@ -1079,59 +686,61 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad } else { ifname[0] = 0; } - - if (!oif || !strcmp(ifname, oif)) { + + if (!iface || !strcmp(iface, ifname)) { + union sockaddr_capwap destaddr; + /* Destination network */ - memset(&dest, 0, sizeof(struct sockaddr_storage)); - dest.ss_family = r->rtm_family; - + memset(&destaddr, 0, sizeof(union sockaddr_capwap)); + destaddr.ss.ss_family = r->rtm_family; + if (tb[RTA_DST]) { - void* buffer = ((r->rtm_family == AF_INET) ? (void*)&((struct sockaddr_in*)&dest)->sin_addr : (void*)&((struct sockaddr_in6*)&dest)->sin6_addr); - - memcpy(buffer, RTA_DATA(tb[RTA_DST]), addrsize); + memcpy(((r->rtm_family == AF_INET) ? (void*)&destaddr.sin.sin_addr : (void*)&destaddr.sin6.sin6_addr), RTA_DATA(tb[RTA_DST]), addrsize); } else if (!r->rtm_dst_len) { defaultgateway = 1; } - + /* Check network */ if (defaultgateway) { if (tb[RTA_GATEWAY]) { - int update = 0; unsigned long metric = (tb[RTA_PRIORITY] ? *(unsigned long*)RTA_DATA(tb[RTA_PRIORITY]) : 0); - - /* Detect primary route */ - if (gatewaytable < r->rtm_table) { - update = 1; - } else if ((gatewaytable == r->rtm_table) && (gatewaymetric > metric)) { - update = 1; - } - - if (update) { - void* buffer = (void*)((r->rtm_family == AF_INET) ? (void*)&(((struct sockaddr_in*)&gateway)->sin_addr) : (void*)&(((struct sockaddr_in6*)&gateway)->sin6_addr)); - + + if ((gatewaytable < r->rtm_table) || ((gatewaytable == r->rtm_table) && (gatewaymetric > metric))) { foundgateway = 1; gatewaytable = r->rtm_table; gatewaymetric = metric; - - memset(&gateway, 0, sizeof(struct sockaddr_storage)); - gateway.ss_family = r->rtm_family; - memcpy(buffer, RTA_DATA(tb[RTA_GATEWAY]), addrsize); + + /* */ + memset(&gateway, 0, sizeof(union sockaddr_capwap)); + + gateway.ss.ss_family = r->rtm_family; + memcpy(((r->rtm_family == AF_INET) ? (void*)&gateway.sin.sin_addr : (void*)&gateway.sin6.sin6_addr), RTA_DATA(tb[RTA_GATEWAY]), addrsize); } } } else if (tb[RTA_PREFSRC]) { - struct sockaddr_storage remotenetwork; - struct sockaddr_storage destnework; + int equal = 0; + union sockaddr_capwap peernetwork; + union sockaddr_capwap destnework; - capwap_get_network_address(remote, &remotenetwork, destmask); - capwap_get_network_address(&dest, &destnework, destmask); + /* Get subnet */ + capwap_get_network_address(peeraddr, &peernetwork, destmask); + capwap_get_network_address(&destaddr, &destnework, destmask); - if (capwap_equal_address(&remotenetwork, &destnework)) { - void* buffer = (void*)((r->rtm_family == AF_INET) ? (void*)&(((struct sockaddr_in*)local)->sin_addr) : (void*)&(((struct sockaddr_in6*)local)->sin6_addr)); + /* Compare subnet */ + if (peernetwork.ss.ss_family == AF_INET) { + if (peernetwork.sin.sin_addr.s_addr == destnework.sin.sin_addr.s_addr) { + equal = 1; + } + } else if (peernetwork.ss.ss_family == AF_INET6) { + if (!memcmp(&peernetwork.sin6.sin6_addr, &destnework.sin6.sin6_addr, sizeof(struct in6_addr))) { + equal = 1; + } + } + if (equal) { result = CAPWAP_ROUTE_LOCAL_ADDRESS; - memset(local, 0, sizeof(struct sockaddr_storage)); - local->ss_family = r->rtm_family; - memcpy(buffer, RTA_DATA(tb[RTA_PREFSRC]), addrsize); + localaddr->ss.ss_family = r->rtm_family; + memcpy(((r->rtm_family == AF_INET) ? (void*)&localaddr->sin.sin_addr : (void*)&localaddr->sin6.sin6_addr), RTA_DATA(tb[RTA_PREFSRC]), addrsize); break; } @@ -1141,20 +750,21 @@ static int capwap_get_routeaddress(struct sockaddr_storage* local, struct sockad } } + /* Next */ h = NLMSG_NEXT(h, status); } } } /* */ - if (!result && foundgateway) { + if ((result == CAPWAP_ROUTE_NOT_FOUND) && foundgateway) { result = CAPWAP_ROUTE_VIA_ADDRESS; - memcpy(local, &gateway, sizeof(struct sockaddr_storage)); + memcpy(localaddr, &gateway, sizeof(union sockaddr_capwap)); } /* */ close(nlsock); - return ((result > 0) ? result : 0); + return result; } /* Get interface flags */ @@ -1179,72 +789,64 @@ static short capwap_get_interface_flags(char* iface) { return req.ifr_flags; } + /* Return local address from remote address */ -int capwap_get_localaddress_by_remoteaddress(struct sockaddr_storage* local, struct sockaddr_storage* remote, char* oif, int ipv6dualstack) { +int capwap_network_get_localaddress(union sockaddr_capwap* localaddr, union sockaddr_capwap* peeraddr, char* iface) { int result; - struct sockaddr_storage remotenorm; - - ASSERT(local != NULL); - ASSERT(remote != NULL); - + + ASSERT(localaddr != NULL); + ASSERT(peeraddr != NULL); + + /* */ + memset(localaddr, 0, sizeof(union sockaddr_capwap)); + /* Check output interface */ - if (oif && !strlen(oif)) { - oif = NULL; + if (iface && !*iface) { + iface = NULL; } - /* Loopback address */ - if (remote->ss_family == AF_INET) { - if (((struct sockaddr_in*)remote)->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { - if (!oif || ((capwap_get_interface_flags(oif) & IFF_LOOPBACK) == IFF_LOOPBACK)) { - memset(local, 0, sizeof(struct sockaddr_storage)); - - local->ss_family = AF_INET; - ((struct sockaddr_in*)local)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - return 1; - } else { - return 0; + /* Check Loopback address */ + if (peeraddr->ss.ss_family == AF_INET) { + if (peeraddr->sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + if (iface && ((capwap_get_interface_flags(iface) & IFF_LOOPBACK) != IFF_LOOPBACK)) { + return -1; } - } - } else if (remote->ss_family == AF_INET6) { - if (!memcmp(&((struct sockaddr_in6*)remote)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr))) { - if (!oif || ((capwap_get_interface_flags(oif) & IFF_LOOPBACK) == IFF_LOOPBACK)) { - memset(local, 0, sizeof(struct sockaddr_storage)); - - local->ss_family = AF_INET6; - memcpy(&((struct sockaddr_in6*)local)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)); - - return 1; - } else { - return 0; - } - } - } - /* Normalize ip address if a ipv4 mapped */ - if (ipv6dualstack && (remote->ss_family == AF_INET6)) { - if (capwap_ipv4_mapped_ipv6(remote, &remotenorm)) { - remote = &remotenorm; - } - } - - /* Get address */ - result = capwap_get_routeaddress(local, remote, oif, ipv6dualstack, RT_TABLE_MAIN); - if (result == CAPWAP_ROUTE_NOT_FOUND) { - return 0; - } else if (result == CAPWAP_ROUTE_VIA_ADDRESS) { - struct sockaddr_storage temp; - - result = capwap_get_routeaddress(&temp, local, oif, ipv6dualstack, RT_TABLE_MAIN); - if (result == CAPWAP_ROUTE_NOT_FOUND) { + /* Loopback */ + localaddr->ss.ss_family = AF_INET; + localaddr->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); return 0; } + } else if (peeraddr->ss.ss_family == AF_INET6) { + if (!memcmp(&peeraddr->sin6.sin6_addr, &in6addr_loopback, sizeof(struct in6_addr))) { + if (iface && ((capwap_get_interface_flags(iface) & IFF_LOOPBACK) != IFF_LOOPBACK)) { + return -1; + } - ASSERT(result == CAPWAP_ROUTE_LOCAL_ADDRESS); - memcpy(local, &temp, sizeof(struct sockaddr_storage)); + localaddr->ss.ss_family = AF_INET6; + memcpy(&localaddr->sin6.sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)); + return 0; + } + } else { + return -1; } - - return 1; + + /* Get address */ + result = capwap_get_routeaddress(localaddr, peeraddr, iface, RT_TABLE_MAIN); + if (result == CAPWAP_ROUTE_NOT_FOUND) { + return -1; + } else if (result == CAPWAP_ROUTE_VIA_ADDRESS) { + union sockaddr_capwap tempaddr; + + result = capwap_get_routeaddress(&tempaddr, localaddr, iface, RT_TABLE_MAIN); + if (result != CAPWAP_ROUTE_LOCAL_ADDRESS) { + return -1; + } + + memcpy(localaddr, &tempaddr, sizeof(union sockaddr_capwap)); + } + + return 0; } /* Retrieve interface list */ @@ -1263,7 +865,7 @@ void capwap_interface_list(struct capwap_network* net, struct capwap_list* list) /* */ for (ifcurrentpos = ifaddrlist; ifcurrentpos != NULL; ifcurrentpos = ifcurrentpos->ifa_next) { struct capwap_list_item* item; - struct sockaddr_storage* addr; + union sockaddr_capwap* addr; /* No loopback interface */ if ((ifcurrentpos->ifa_flags & IFF_LOOPBACK) != 0) { @@ -1276,27 +878,28 @@ void capwap_interface_list(struct capwap_network* net, struct capwap_list* list) } /* Filter family */ - if ((net->sock_family != AF_UNSPEC) && (net->sock_family != ifcurrentpos->ifa_addr->sa_family)) { + if (net->localaddr.ss.ss_family != ifcurrentpos->ifa_addr->sa_family) { continue; } /* Filter interface */ - if ((net->bind_interface[0] != 0) && (strcmp(net->bind_interface, ifcurrentpos->ifa_name) != 0)) { + if (*net->bindiface && strcmp(net->bindiface, ifcurrentpos->ifa_name)) { continue; } /* Add local address */ - item = capwap_itemlist_create(sizeof(struct sockaddr_storage)); - addr = (struct sockaddr_storage*)item->item; + item = capwap_itemlist_create(sizeof(union sockaddr_capwap)); + addr = (union sockaddr_capwap*)item->item; - memset(addr, 0, sizeof(struct sockaddr_storage)); - addr->ss_family = ifcurrentpos->ifa_addr->sa_family; - CAPWAP_SET_NETWORK_PORT(addr, net->bind_sock_ctrl_port); + memset(addr, 0, sizeof(union sockaddr_capwap)); + addr->ss.ss_family = ifcurrentpos->ifa_addr->sa_family; - if (addr->ss_family == AF_INET) { - memcpy(&((struct sockaddr_in*)addr)->sin_addr, &((struct sockaddr_in*)ifcurrentpos->ifa_addr)->sin_addr, sizeof(struct in_addr)); - } else if (addr->ss_family == AF_INET6) { - memcpy(&((struct sockaddr_in6*)addr)->sin6_addr, &((struct sockaddr_in6*)ifcurrentpos->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + if (addr->ss.ss_family == AF_INET) { + memcpy(&addr->sin.sin_addr, &((struct sockaddr_in*)ifcurrentpos->ifa_addr)->sin_addr, sizeof(struct in_addr)); + addr->sin.sin_port = htons(CAPWAP_CONTROL_PORT); + } else if (addr->ss.ss_family == AF_INET6) { + memcpy(&addr->sin6.sin6_addr, &((struct sockaddr_in6*)ifcurrentpos->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + addr->sin6.sin6_port = htons(CAPWAP_CONTROL_PORT); } /* Add address */ @@ -1304,10 +907,9 @@ void capwap_interface_list(struct capwap_network* net, struct capwap_list* list) } /* Free */ - freeifaddrs(ifaddrlist); + freeifaddrs(ifaddrlist); } - /* */ char* capwap_printf_macaddress(char* buffer, const uint8_t* macaddress, int type) { if (type == MACADDRESS_EUI48_LENGTH) { diff --git a/src/common/capwap_network.h b/src/common/capwap_network.h index 9c08991..604012f 100644 --- a/src/common/capwap_network.h +++ b/src/common/capwap_network.h @@ -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); diff --git a/src/common/capwap_protocol.c b/src/common/capwap_protocol.c index 568c199..2fa8c56 100644 --- a/src/common/capwap_protocol.c +++ b/src/common/capwap_protocol.c @@ -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; diff --git a/src/common/capwap_protocol.h b/src/common/capwap_protocol.h index 8118343..624177b 100644 --- a/src/common/capwap_protocol.h +++ b/src/common/capwap_protocol.h @@ -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__ */ diff --git a/src/common/capwap_socket.c b/src/common/capwap_socket.c index 94c2e18..5e8478e 100644 --- a/src/common/capwap_socket.c +++ b/src/common/capwap_socket.c @@ -1,4 +1,5 @@ #include "capwap.h" +#include "capwap_network.h" #include "capwap_socket.h" #include @@ -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 */ diff --git a/src/common/capwap_socket.h b/src/common/capwap_socket.h index 6181ab8..0544df7 100644 --- a/src/common/capwap_socket.h +++ b/src/common/capwap_socket.h @@ -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); diff --git a/src/common/md5.c b/src/common/md5.c deleted file mode 100644 index 1b80da9..0000000 --- a/src/common/md5.c +++ /dev/null @@ -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; -} diff --git a/src/common/md5.h b/src/common/md5.h deleted file mode 100644 index cbe405b..0000000 --- a/src/common/md5.h +++ /dev/null @@ -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); diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index 471b10a..3a54ad6 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -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; } /* */ diff --git a/src/wtp/binding/ieee80211/wifi_drivers.h b/src/wtp/binding/ieee80211/wifi_drivers.h index d3b023f..61ea2b6 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.h +++ b/src/wtp/binding/ieee80211/wifi_drivers.h @@ -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); diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.c b/src/wtp/binding/ieee80211/wifi_nl80211.c index a9b41f3..9185a06 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.c +++ b/src/wtp/binding/ieee80211/wifi_nl80211.c @@ -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; diff --git a/src/wtp/kmod/Makefile b/src/wtp/kmod/Makefile index 8a24b9e..1cabb48 100644 --- a/src/wtp/kmod/Makefile +++ b/src/wtp/kmod/Makefile @@ -2,4 +2,7 @@ obj-m += smartcapwap.o smartcapwap-y := \ main.o \ - netlinkapp.o + netlinkapp.o \ + socket.o \ + capwap.o \ + capwap_private.o diff --git a/src/wtp/kmod/capwap.c b/src/wtp/kmod/capwap.c new file mode 100644 index 0000000..c77f000 --- /dev/null +++ b/src/wtp/kmod/capwap.c @@ -0,0 +1,621 @@ +#include "config.h" +#include +#include +#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; +} diff --git a/src/wtp/kmod/capwap.h b/src/wtp/kmod/capwap.h new file mode 100644 index 0000000..0738ecd --- /dev/null +++ b/src/wtp/kmod/capwap.h @@ -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__ */ diff --git a/src/wtp/kmod/capwap_private.c b/src/wtp/kmod/capwap_private.c new file mode 100644 index 0000000..487bad3 --- /dev/null +++ b/src/wtp/kmod/capwap_private.c @@ -0,0 +1,164 @@ +#include "config.h" +#include +#include +#include +#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); +} diff --git a/src/wtp/kmod/capwap_private.h b/src/wtp/kmod/capwap_private.h new file mode 100644 index 0000000..da04a7d --- /dev/null +++ b/src/wtp/kmod/capwap_private.h @@ -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__ */ + diff --git a/src/wtp/kmod/capwap_rfc.h b/src/wtp/kmod/capwap_rfc.h new file mode 100644 index 0000000..6fa149c --- /dev/null +++ b/src/wtp/kmod/capwap_rfc.h @@ -0,0 +1,172 @@ +#ifndef __KMOD_CAPWAP_RFC_HEADER__ +#define __KMOD_CAPWAP_RFC_HEADER__ + +#include +#include + +/* */ +#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__ */ diff --git a/src/wtp/kmod/config.h b/src/wtp/kmod/config.h new file mode 100644 index 0000000..207855b --- /dev/null +++ b/src/wtp/kmod/config.h @@ -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__ */ + diff --git a/src/wtp/kmod/main.c b/src/wtp/kmod/main.c index 2161e4c..d7f2c8d 100644 --- a/src/wtp/kmod/main.c +++ b/src/wtp/kmod/main.c @@ -1,23 +1,31 @@ +#include "config.h" #include #include #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 "); diff --git a/src/wtp/kmod/netlinkapp.c b/src/wtp/kmod/netlinkapp.c index f03d577..bfb2850 100644 --- a/src/wtp/kmod/netlinkapp.c +++ b/src/wtp/kmod/netlinkapp.c @@ -1,5 +1,7 @@ +#include "config.h" #include #include +#include #include #include #include @@ -8,154 +10,200 @@ #include #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); } diff --git a/src/wtp/kmod/netlinkapp.h b/src/wtp/kmod/netlinkapp.h index e281da7..6c8d0e8 100644 --- a/src/wtp/kmod/netlinkapp.h +++ b/src/wtp/kmod/netlinkapp.h @@ -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__ */ diff --git a/src/wtp/kmod/nlsmartcapwap.h b/src/wtp/kmod/nlsmartcapwap.h index 3fe27f9..709756f 100644 --- a/src/wtp/kmod/nlsmartcapwap.h +++ b/src/wtp/kmod/nlsmartcapwap.h @@ -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__ */ diff --git a/src/wtp/kmod/socket.c b/src/wtp/kmod/socket.c new file mode 100644 index 0000000..e56aecb --- /dev/null +++ b/src/wtp/kmod/socket.c @@ -0,0 +1,257 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; + } +} diff --git a/src/wtp/kmod/socket.h b/src/wtp/kmod/socket.h new file mode 100644 index 0000000..f8c2a9e --- /dev/null +++ b/src/wtp/kmod/socket.h @@ -0,0 +1,45 @@ +#ifndef __KMOD_SOCKET_HEADER__ +#define __KMOD_SOCKET_HEADER__ + +#include +#include +#include +#include + +/* */ +#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__ */ diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index 587d3c6..d26b244 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -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); } diff --git a/src/wtp/wtp.h b/src/wtp/wtp.h index 33c0479..2b1487d 100644 --- a/src/wtp/wtp.h +++ b/src/wtp/wtp.h @@ -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; }; diff --git a/src/wtp/wtp_dfa.c b/src/wtp/wtp_dfa.c index ee959e9..3fd4ec5 100644 --- a/src/wtp/wtp_dfa.c +++ b/src/wtp/wtp_dfa.c @@ -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); + } } } diff --git a/src/wtp/wtp_dfa.h b/src/wtp/wtp_dfa.h index 2b80c5a..1c94f5e 100644 --- a/src/wtp/wtp_dfa.h +++ b/src/wtp/wtp_dfa.h @@ -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__ */ diff --git a/src/wtp/wtp_dfa_configure.c b/src/wtp/wtp_dfa_configure.c index 52781df..974bf4f 100644 --- a/src/wtp/wtp_dfa_configure.c +++ b/src/wtp/wtp_dfa_configure.c @@ -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(); diff --git a/src/wtp/wtp_dfa_datacheck.c b/src/wtp/wtp_dfa_datacheck.c index 41cb08d..b9f05b9 100644 --- a/src/wtp/wtp_dfa_datacheck.c +++ b/src/wtp/wtp_dfa_datacheck.c @@ -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(); diff --git a/src/wtp/wtp_dfa_discovery.c b/src/wtp/wtp_dfa_discovery.c index 25582d1..ee6cae5 100644 --- a/src/wtp/wtp_dfa_discovery.c +++ b/src/wtp/wtp_dfa_discovery.c @@ -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 */ diff --git a/src/wtp/wtp_dfa_dtls.c b/src/wtp/wtp_dfa_dtls.c index fb54862..466998b 100644 --- a/src/wtp/wtp_dfa_dtls.c +++ b/src/wtp/wtp_dfa_dtls.c @@ -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); diff --git a/src/wtp/wtp_dfa_idle.c b/src/wtp/wtp_dfa_idle.c index 9a5162f..de86bfd 100644 --- a/src/wtp/wtp_dfa_idle.c +++ b/src/wtp/wtp_dfa_idle.c @@ -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; } } } diff --git a/src/wtp/wtp_dfa_join.c b/src/wtp/wtp_dfa_join.c index 87d4211..d720878 100644 --- a/src/wtp/wtp_dfa_join.c +++ b/src/wtp/wtp_dfa_join.c @@ -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(); diff --git a/src/wtp/wtp_dfa_run.c b/src/wtp/wtp_dfa_run.c index e3bc95c..891504e 100644 --- a/src/wtp/wtp_dfa_run.c +++ b/src/wtp/wtp_dfa_run.c @@ -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; } } } diff --git a/src/wtp/wtp_kmod.c b/src/wtp/wtp_kmod.c index 7b73c6c..efd48af 100644 --- a/src/wtp/wtp_kmod.c +++ b/src/wtp/wtp_kmod.c @@ -1,4 +1,5 @@ #include "wtp.h" +#include "wtp_dfa.h" #include #include #include @@ -84,23 +85,16 @@ static int wtp_kmod_ack_handler(struct nl_msg* msg, void* arg) { /* */ static int wtp_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { switch (gnlh->cmd) { - case NLSMARTCAPWAP_CMD_FRAME: { - struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)data; - - if (tb_msg[NLSMARTCAPWAP_ATTR_FRAME]) { - uint32_t sig_dbm = (tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] ? nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM]) : 0); - uint16_t rate = (tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE] ? ((uint16_t)nla_get_u8(tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE])) * 5 : 0); /* Convert rate 500Kbps to 100Kbps */ - int nativeframe = (tb_msg[SMARTCAPWAP_FLAGS_TUNNEL_8023] ? 0 : 1); - - /* Forwards the frame to AC */ - wifi_wlan_send_frame(interface->wlan, (uint8_t*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nativeframe, (uint8_t)sig_dbm, 0, rate); - } - + case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: { + wtp_recv_data_keepalive(); break; } - default: { - capwap_logging_debug("*** wtp_kmod_event_handler: %d", (int)gnlh->cmd); + case NLSMARTCAPWAP_CMD_RECV_DATA: { + if (tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { + wtp_recv_data(nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME])); + } + break; } } @@ -204,15 +198,177 @@ static void wtp_kmod_event_receive(int fd, void** params, int paramscount) { } /* */ -int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags) { +int wtp_kmod_bind(uint16_t family) { + int result; + struct nl_msg* msg; + struct sockaddr_storage sockaddr; + + ASSERT((family == AF_INET) || (family == AF_INET6)); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); + sockaddr.ss_family = family; + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu) { + int result; + struct nl_msg* msg; + + ASSERT(sockaddr != NULL); + ASSERT((sockaddr->ss_family == AF_INET) || (sockaddr->ss_family == AF_INET6)); + ASSERT(sessionid != NULL); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_send_keepalive(void) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_resetsession(void) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_RESET, 0); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); + nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, frame); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); + + if (rssi) { + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RSSI, rssi); + } + + if (snr) { + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_SNR, snr); + } + + if (rate) { + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_RATE, rate); + } + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags) { int result; struct nl_msg* msg; struct capwap_list_item* itemlist; struct wtp_kmod_iface_handle* interface; uint32_t kmodflags = 0; - uint16_t subtype_mgmt = 0; - uint16_t subtype_ctrl = 0; - uint16_t subtype_data = 0; ASSERT(wlan != NULL); @@ -226,91 +382,38 @@ int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_ interface = (struct wtp_kmod_iface_handle*)itemlist->item; memset(interface, 0, sizeof(struct wtp_kmod_iface_handle)); - /* Socket management */ - if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) { - interface->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!interface->nl_cb) { - capwap_itemlist_free(itemlist); - return -1; - } - - nl_cb_set(interface->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL); - nl_cb_set(interface->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, (void*)interface); - - interface->nl = nl_create_handle(interface->nl_cb); - if (interface->nl) { - interface->nl_fd = nl_socket_get_fd(interface->nl); - } else { - nl_cb_put(interface->nl_cb); - capwap_itemlist_free(itemlist); - return -1; - } - } - /* */ msg = nlmsg_alloc(); if (!msg) { - if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) { - nl_socket_free(interface->nl); - nl_cb_put(interface->nl_cb); - } - capwap_itemlist_free(itemlist); return -1; } /* Set flags */ - switch (mode) { - case WTP_KMOD_MODE_LOCAL: { - break; - } - - case WTP_KMOD_MODE_TUNNEL_USERMODE: { - kmodflags |= SMARTCAPWAP_FLAGS_SEND_USERSPACE | SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME; - subtype_data = 0xffff; - - if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { - kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023; - } - - break; - } - - case WTP_KMOD_MODE_TUNNEL_KERNELMODE: { - kmodflags |= SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME; - subtype_data = 0xffff; - - if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { - kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023; - } - - break; - } + if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { + kmodflags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023; } /* */ genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0); nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, wlan->radioid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlan->wlanid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, kmodflags); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, subtype_mgmt); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, subtype_ctrl); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, subtype_data); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, 0x0000); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, 0x0000); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff); /* */ - result = wtp_kmod_send_and_recv(interface->nl, interface->nl_cb, msg, NULL, NULL); + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); if (!result) { - interface->mode = mode; interface->flags = flags; interface->wlan = wlan; /* */ capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist); - if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) { - g_wtp.kmodhandle.interfaceconnectioncount++; - } } else { - nl_socket_free(interface->nl); - nl_cb_put(interface->nl_cb); capwap_itemlist_free(itemlist); } @@ -350,14 +453,6 @@ int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) { struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; if (interface->wlan == wlan) { - nl_socket_free(interface->nl); - nl_cb_put(interface->nl_cb); - - /* Free item */ - if (interface->mode == WTP_KMOD_MODE_TUNNEL_USERMODE) { - g_wtp.kmodhandle.interfaceconnectioncount--; - } - capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist)); break; } @@ -376,9 +471,7 @@ int wtp_kmod_isconnected(void) { /* */ int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) { - int i; - struct capwap_list_item* itemlist; - int kmodcount = (wtp_kmod_isconnected() ? 1 + g_wtp.kmodhandle.interfaceconnectioncount : 0); + int kmodcount = (wtp_kmod_isconnected() ? 1 : 0); /* */ if (!kmodcount) { @@ -401,27 +494,6 @@ int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb; events[0].paramscount = 2; - /* */ - for (i = 1, itemlist = g_wtp.kmodhandle.interfaces->first; itemlist; itemlist = itemlist->next) { - struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; - - /* */ - if (interface->nl_fd) { - fds[i].fd = interface->nl_fd; - fds[i].events = POLLIN | POLLERR | POLLHUP; - - /* */ - events[i].event_handler = wtp_kmod_event_receive; - events[i].params[0] = (void*)interface->nl; - events[i].params[1] = (void*)interface->nl_cb; - events[i].paramscount = 2; - - /* */ - i++; - } - } - - ASSERT(kmodcount == i); return kmodcount; } @@ -446,7 +518,7 @@ int wtp_kmod_init(void) { g_wtp.kmodhandle.nl_fd = nl_socket_get_fd(g_wtp.kmodhandle.nl); /* Get nlsmartcapwap netlink family */ - g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, SMARTCAPWAP_GENL_NAME); + g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) { capwap_logging_warning("Unable to found kernel module"); wtp_kmod_free(); diff --git a/src/wtp/wtp_kmod.h b/src/wtp/wtp_kmod.h index 41cb69a..98e9b1b 100644 --- a/src/wtp/wtp_kmod.h +++ b/src/wtp/wtp_kmod.h @@ -8,22 +8,12 @@ #define nl_sock nl_handle #endif -/* */ -#define WTP_KMOD_MODE_LOCAL 0x00000001 -#define WTP_KMOD_MODE_TUNNEL_USERMODE 0x00000002 -#define WTP_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003 - /* */ #define WTP_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 #define WTP_KMOD_FLAGS_TUNNEL_8023 0x00000001 /* */ struct wtp_kmod_iface_handle { - struct nl_sock* nl; - int nl_fd; - struct nl_cb* nl_cb; - - uint32_t mode; uint32_t flags; struct wifi_wlan* wlan; }; @@ -37,7 +27,6 @@ struct wtp_kmod_handle { /* */ struct capwap_list* interfaces; - int interfaceconnectioncount; }; /* */ @@ -57,7 +46,16 @@ int wtp_kmod_isconnected(void); int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count); /* */ -int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags); +int wtp_kmod_bind(uint16_t family); +int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu); +int wtp_kmod_resetsession(void); + +/* */ +int wtp_kmod_send_keepalive(void); +int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate); + +/* */ +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags); int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan); #endif /* __WTP_KMOD_HEADER__ */ diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index 8be1389..bbac664 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -3,6 +3,7 @@ #include "capwap_list.h" #include "wtp_radio.h" #include "wtp_dfa.h" +#include "wtp_kmod.h" /* */ #define WTP_UPDATE_FREQUENCY_DSSS 1 @@ -50,18 +51,6 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { return 0; } -/* */ -static int wtp_radio_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) { - struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)param; - - ASSERT(param != NULL); - ASSERT(frame != NULL); - ASSERT(length > 0); - - /* Send packet */ - return wtp_send_data_packet(wlan->radio->radioid, wlan->wlanid, frame, length, nativeframe, rssi, snr, rate, bssaddress, bssaddresstype); -} - /* */ static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { uint8_t* macaddress = (uint8_t*)key; @@ -538,11 +527,10 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani } /* */ -struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { +static struct wtp_radio_wlan* __wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { struct capwap_list_item* itemwlan; ASSERT(radio != NULL); - ASSERT(bssid != NULL); /* Retrieve BSS */ for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { @@ -555,6 +543,27 @@ struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint return NULL; } +/* */ +struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { + int i; + + ASSERT(bssid != NULL); + + if (radio) { + return __wtp_radio_search_wlan(radio, bssid); + } + + /* Search from any radio */ + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio_wlan* wlansearch = __wtp_radio_search_wlan((struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i), bssid); + if (wlansearch) { + return wlansearch; + } + } + + return NULL; +} + /* */ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length) { struct wtp_radio* radio; @@ -580,7 +589,6 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons } } } - } /* */ @@ -638,8 +646,8 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa /* Wlan configuration */ memset(¶ms, 0, sizeof(struct wlan_startap_params)); - params.send_frame = wtp_radio_send_frame_to_ac; - params.send_frame_to_ac_cbparam = (void*)wlan; + params.radioid = addwlan->radioid; + params.wlanid = addwlan->wlanid; params.ssid = (const char*)addwlan->ssid; params.ssid_hidden = addwlan->suppressssid; params.capability = addwlan->capability; @@ -736,9 +744,8 @@ uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet) { return CAPWAP_RESULTCODE_FAILURE; } - if (wifi_station_deauthorize(radio->devicehandle, deletestation->address)) { - return CAPWAP_RESULTCODE_FAILURE; - } + /* */ + wifi_station_deauthorize(radio->devicehandle, deletestation->address); return CAPWAP_RESULTCODE_SUCCESS; } diff --git a/version.m4 b/version.m4 deleted file mode 100644 index 1bb973c..0000000 --- a/version.m4 +++ /dev/null @@ -1,5 +0,0 @@ -dnl define the SmartCAPWAP version -define([PRODUCT_NAME], [SmartCAPWAP]) -define([PRODUCT_TARNAME], [smartcapwap]) -define([PRODUCT_VERSION], [1.0.0]) -define([PRODUCT_BUGREPORT], [vemax78@gmail.com])