diff options
author | Thierry Strudel <tstrudel@google.com> | 2017-05-23 16:11:15 -0700 |
---|---|---|
committer | Thierry Strudel <tstrudel@google.com> | 2017-05-23 22:58:01 -0700 |
commit | 582b9e5c388f74eeafad876c81492c81bf1f3945 (patch) | |
tree | c6f1f742a3f9554caa3ceb2bc7d37a4f2c31ad1e | |
parent | db2e7b222236f6aec16f83c5e0ca0878d164ee4e (diff) | |
download | ipacfg-mgr-582b9e5c388f74eeafad876c81492c81bf1f3945.tar.gz |
msm8998: Update to 07.00.00.279.162
msm8998: from vendor/qcom/opensource/data-ipa-cfg-mgr
f554a9b Promotion of data.lnx.6.4.9-00026.
dc61b57 IPACM: Add support on IPACM-HAL for Android-O
e7ba062 hal: deal with unsatisfied dependencies
0b00b18 hal: 1.0: Initial commit
Test: build, boot, sanity checks
Bug: 62038492
Change-Id: I04f1afb807fb1e43dc52f87963b0713716bc0586
Signed-off-by: Thierry Strudel <tstrudel@google.com>
32 files changed, 3615 insertions, 155 deletions
diff --git a/msm8998/hal/Android.mk b/msm8998/hal/Android.mk new file mode 100644 index 0000000..c24a611 --- /dev/null +++ b/msm8998/hal/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_ARM_MODE := arm +LOCAL_SRC_FILES := src/CtUpdateAmbassador.cpp \ + src/HAL.cpp \ + src/IpaEventRelay.cpp \ + src/LocalLogBuffer.cpp \ + src/OffloadStatistics.cpp \ + src/PrefixParser.cpp +LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc +LOCAL_MODULE := liboffloadhal +LOCAL_CPP_FLAGS := -Wall -Werror +LOCAL_SHARED_LIBRARIES := libhwbinder \ + libhidlbase \ + libhidltransport \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + android.hardware.tetheroffload.config@1.0 \ + android.hardware.tetheroffload.control@1.0 +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib +LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64 +include $(BUILD_SHARED_LIBRARY) diff --git a/msm8998/hal/inc/CtUpdateAmbassador.h b/msm8998/hal/inc/CtUpdateAmbassador.h new file mode 100644 index 0000000..d4890f3 --- /dev/null +++ b/msm8998/hal/inc/CtUpdateAmbassador.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _CT_UPDATE_AMBASSADOR_H_ +#define _CT_UPDATE_AMBASSADOR_H_ +/* External Includes */ +#include <hidl/HidlTransportSupport.h> + +/* HIDL Includes */ +#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h> + +/* Internal Includes */ +#include "IOffloadManager.h" + +/* Namespace pollution avoidance */ +using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback; +using ::android::hardware::tetheroffload::control::V1_0::NetworkProtocol; +using HALIpAddrPortPair = ::android::hardware::tetheroffload::control::V1_0::IPv4AddrPortPair; +using HALNatTimeoutUpdate = ::android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate; + +using IpaIpAddrPortPair = ::IOffloadManager::ConntrackTimeoutUpdater::IpAddrPortPair; +using IpaNatTimeoutUpdate = ::IOffloadManager::ConntrackTimeoutUpdater::NatTimeoutUpdate; +using IpaL4Protocol = ::IOffloadManager::ConntrackTimeoutUpdater::L4Protocol; + + +class CtUpdateAmbassador : public IOffloadManager::ConntrackTimeoutUpdater { +public: + CtUpdateAmbassador(const ::android::sp<ITetheringOffloadCallback>& /* cb */); + /* ------------------- CONNTRACK TIMEOUT UPDATER ------------------------ */ + void updateTimeout(IpaNatTimeoutUpdate /* update */); +private: + static bool translate(IpaNatTimeoutUpdate /* in */, HALNatTimeoutUpdate& /* out */); + static bool translate(IpaIpAddrPortPair /* in */, HALIpAddrPortPair& /* out */); + static bool L4ToNetwork(IpaL4Protocol /* in */, NetworkProtocol& /* out */); + const ::android::sp<ITetheringOffloadCallback>& mFramework; +}; /* CtUpdateAmbassador */ +#endif /* _CT_UPDATE_AMBASSADOR_H_ */
\ No newline at end of file diff --git a/msm8998/hal/inc/HAL.h b/msm8998/hal/inc/HAL.h new file mode 100644 index 0000000..622a67e --- /dev/null +++ b/msm8998/hal/inc/HAL.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _HAL_H_ +#define _HAL_H_ + +/* HIDL Includes */ +#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> +#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h> +#include <hidl/HidlTransportSupport.h> + +/* External Includes */ +#include <string> +#include <vector> + +/* Internal Includes */ +#include "CtUpdateAmbassador.h" +#include "IOffloadManager.h" +#include "IpaEventRelay.h" +#include "LocalLogBuffer.h" + +/* Avoid the namespace litering everywhere */ +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::joinRpcThreadpool; +using ::android::hardware::Return; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + +using RET = ::IOffloadManager::RET; +using Prefix = ::IOffloadManager::Prefix; + +using ::std::map; +using ::std::string; +using ::std::vector; + +using ::android::hardware::tetheroffload::config::V1_0::IOffloadConfig; +using ::android::hardware::tetheroffload::control::V1_0::IOffloadControl; + +using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback; + + +class HAL : public IOffloadControl, IOffloadConfig { +public: + /* Static Const Definitions */ + static const uint32_t UDP_SUBSCRIPTIONS = + NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY; + static const uint32_t TCP_SUBSCRIPTIONS = + NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY; + + /* Interface to IPACM */ + /** + * @TODO This will likely need to be extended into a proper FactoryPattern + * when version bumps are needed. + * + * This makeIPAHAL function would move to a HALFactory class. Each HAL could + * then be versioned (class HAL_V1, class HAL_V2, etc) and inherit from a base class HAL. + * Then the version number in this function could be used to decide which one to return + * (if any). + * + * IPACM does not need to talk directly back to the returned HAL class. The other methods that + * IPACM needs to call are covered by registering the event listeners. If IPACM did need to + * talk directly back to the HAL object, without HAL registering a callback, these methods would + * need to be defined in the HAL base class. + * + * This would slightly break backwards compatibility so it should be discouraged; however, the + * base class could define a sane default implementation and not require that the child class + * implement this new method. This "sane default implementation" might only be possible in the + * case of listening to async events; if IPACM needs to query something, then this would not + * be backwards compatible and should be done via registering a callback so that IPACM knows + * this version of HAL supports that functionality. + * + * The above statements assume that only one version of the HAL will be instantiated at a time. + * Yet, it seems possible that a HAL_V1 and HAL_V2 service could both be registered, extending + * support to both old and new client implementations. It would be difficult to multiplex + * information from both versions. Additionally, IPACM would be responsible for instantiating + * two HALs (makeIPAHAL(1, ...); makeIPAHAL(2, ...)) which makes signaling between HAL versions + * (see next paragraph) slightly more difficult but not impossible. + * + * If concurrent versions of HAL are required, there will likely need to only be one master. + * Whichever version of HAL receives a client first may be allowed to take over control while + * other versions would be required to return failures (ETRYAGAIN: another version in use) until + * that version of the client relinquishes control. This should work seemlessly because we + * currently have an assumption that only one client will be present in system image. + * Logically, that client will have only a single version (or if it supports multiple, it will + * always attempt the newest version of HAL before falling back) and therefore no version + * collisions could possibly occur. + * + * Dislaimer: + * ========== + * Supporting multiple versions of an interface, in the same code base, at runtime, comes with a + * significant carrying cost and overhead in the form of developer headaches. This should not + * be done lightly and should be extensively scoped before committing to the effort. + * + * Perhaps the notion of minor version could be introduced to bridge the gaps created above. + * For example, 1.x and 1.y could be ran concurrently and supported from the same IPACM code. + * Yet, a major version update, would not be backwards compatible. This means that a 2.x HAL + * could not linked into the same IPACM code base as a 1.x HAL. + */ + static HAL* makeIPAHAL(int /* version */, IOffloadManager* /* mgr */); + + /* IOffloadConfig */ + Return<void> setHandles( + const hidl_handle& /* fd1 */, + const hidl_handle& /* fd2 */, + setHandles_cb /* hidl_cb */); + + /* IOffloadControl */ + Return<void> initOffload( + const ::android::sp<ITetheringOffloadCallback>& /* cb */, + initOffload_cb /* hidl_cb */); + Return<void> stopOffload( + stopOffload_cb /* hidl_cb */); + Return<void> setLocalPrefixes( + const hidl_vec<hidl_string>& /* prefixes */, + setLocalPrefixes_cb /* hidl_cb */); + Return<void> getForwardedStats( + const hidl_string& /* upstream */, + getForwardedStats_cb /* hidl_cb */); + Return<void> setDataLimit( + const hidl_string& /* upstream */, + uint64_t /* limit */, + setDataLimit_cb /* hidl_cb */); + Return<void> setUpstreamParameters( + const hidl_string& /* iface */, + const hidl_string& /* v4Addr */, + const hidl_string& /* v4Gw */, + const hidl_vec<hidl_string>& /* v6Gws */, + setUpstreamParameters_cb /* hidl_cb */); + Return<void> addDownstream( + const hidl_string& /* iface */, + const hidl_string& /* prefix */, + addDownstream_cb /* hidl_cb */); + Return<void> removeDownstream( + const hidl_string& /* iface */, + const hidl_string& /* prefix */, + removeDownstream_cb /* hidl_cb */); + +private: + typedef struct BoolResult { + bool success; + string errMsg; + } boolResult_t; + + HAL(IOffloadManager* /* mgr */); + void registerAsSystemService(const char* /* name */); + + void doLogcatDump(); + + static BoolResult makeInputCheckFailure(string /* customErr */); + static BoolResult ipaResultToBoolResult(RET /* in */); + + static vector<string> convertHidlStrToStdStr(hidl_vec<hidl_string> /* in */); + + void registerEventListeners(); + void registerIpaCb(); + void registerCtCb(); + void unregisterEventListeners(); + void unregisterIpaCb(); + void unregisterCtCb(); + + void clearHandles(); + + bool isInitialized(); + + IOffloadManager* mIPA; + hidl_handle mHandle1; + hidl_handle mHandle2; + LocalLogBuffer mLogs; + ::android::sp<ITetheringOffloadCallback> mCb; + IpaEventRelay *mCbIpa; + CtUpdateAmbassador *mCbCt; +}; /* HAL */ +#endif /* _HAL_H_ */ diff --git a/msm8998/hal/inc/IOffloadManager.h b/msm8998/hal/inc/IOffloadManager.h new file mode 100644 index 0000000..6a357b3 --- /dev/null +++ b/msm8998/hal/inc/IOffloadManager.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _I_OFFLOAD_MANAGER_H_ +#define _I_OFFLOAD_MANAGER_H_ + +/* External Includes */ +#include <sys/types.h> + +/* Internal Includes */ +#include "OffloadStatistics.h" + + +class IOffloadManager { +public: + enum RET { + FAIL_TOO_MANY_PREFIXES = -6, + FAIL_UNSUPPORTED = -5, + FAIL_INPUT_CHECK = -4, + FAIL_HARDWARE = -3, + FAIL_UNNEEDED = -2, + FAIL_TRY_AGAIN = -1, + SUCCESS = 0, + SUCCESS_DUPLICATE_CONFIG = 1, + SUCCESS_NO_OP = 2, + SUCCESS_OPTIMIZED = 3 + }; /* RET */ + + enum IP_FAM { + V4 = 0, + V6 = 1, + INVALID = 2 + }; /* IP_FAM */ + + /* Overloading to use for addresses as well */ + typedef struct Prefix { + IP_FAM fam; + uint32_t v4Addr; + uint32_t v4Mask; + uint32_t v6Addr[4]; + uint32_t v6Mask[4]; + } prefix_t; + + /* ---------------------------- LIFECYCLE ------------------------------- */ + virtual ~IOffloadManager(){} + + /* ---------------------- ASYNC EVENT CALLBACKS ------------------------- */ + class IpaEventListener { + public: + enum StoppedReason { + /** + * Offload was stopped due to the configuration being removed via + * setUpstreamParameters/removeDownstream. + */ + REQUESTED, + /** + * Offload was stopped due to an internal (to IPA or modem) error. + * + * Statistics may be temporarily unavailable. + */ + ERROR, + /** + * Offload was stopped because the upstream connection has + * migrated to unsupported radio access technology. + * + * Statistics will still be available. + */ + UNSUPPORTED + }; /* StoppedReason */ + virtual ~IpaEventListener(){} + /** + * Called when Offload first begins to occur on any upstream and + * tether interface pair. It should be paired with an onOffloadStopped + * call. + */ + virtual void onOffloadStarted(){} + /** + * Called when Offload stops occurring on all upstream and tether + * interface pairs. It comes after a call to onOffloadStarted. + * + * @param reason Reason that Offload was stopped + */ + virtual void onOffloadStopped(StoppedReason /* reason */){} + /** + * Called when the hardware can support Offload again. + * + * Any statistics that were previously unavailable, may be queried + * again at this time. + */ + virtual void onOffloadSupportAvailable(){} + /** + * Called when the limit set via setQuota has expired. + * + * It is implied that Offload has been stopped on all upstream and + * tether interface pairs when this callback is called. + */ + virtual void onLimitReached(){} + }; /* IpaEventListener */ + + /** + * Request notifications about asynchronous events that occur in hardware. + * + * The calling client must be able to handle the callback on a separate + * thread (i.e. their implementation of IpaEventListener must be thread + * safe). + * + * @return SUCCESS iff callback successfully registered + * + * Remarks: This can't really be allowed to fail. + */ + virtual RET registerEventListener(IpaEventListener* /* listener */) = 0; + /** + * Unregister a previously registered listener. + * + * @return SUCCESS iff callback successfully unregistered + * FAIL_INPUT_CHECK if callback was never registered + */ + virtual RET unregisterEventListener(IpaEventListener* /* listener */) = 0; + + class ConntrackTimeoutUpdater { + public: + enum L4Protocol { + TCP = 0, + UDP = 1 + }; /* L4Protocol */ + typedef struct IpAddrPortPair { + uint32_t ipAddr; + uint16_t port; + } ipAddrPortPair_t; + typedef struct NatTimeoutUpdate { + IpAddrPortPair src; + IpAddrPortPair dst; + L4Protocol proto; + } natTimeoutUpdate_t; + virtual ~ConntrackTimeoutUpdater(){} + virtual void updateTimeout(NatTimeoutUpdate /* update */) {} + }; /* ConntrackTimeoutUpdater */ + + /** + * Register a callback that may be called if the OffloadManager wants to + * update the timeout value in conntrack of kernel. + * + * The calling client must be able to handle the callback on a separate + * thread (i.e. their implementation of ConntrackTimeoutUpdater must be + * thread safe) + * + * @return SUCCESS iff callback successfully registered + * + * Remarks: This can't really be allowed to fail + */ + virtual RET registerCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */) = 0; + /** + * Unregister a previously registered callback. + * + * @return SUCCESS iff callback successfully unregistered + * FAIL_INPUT_CHECK if callback was never registered + */ + virtual RET unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */) = 0; + + /* ----------------------------- CONFIG --------------------------------- */ + /** + * Provide a file descriptor for use with conntrack library + * + * @param fd File Descriptor that has been opened and bound to groups + * @param groups Groups (bit mask) that fd has been bound to + * + * @return SUCCESS iff IOffloadManager needed this file descriptor and + * it was properly bound. + * FAIL_INPUT_CHECK if IOffloadManager needed this file descriptor + * but it was found to not be properly bound + * FAIL_UNNEEDED if IOffloadManager determined that it does not need + * a file descriptor bound to these groups. + */ + virtual RET provideFd(int /* fd */, unsigned int /* group */) = 0; + /** + * Indicate that IOffloadManager <b>must</b> cease using all file + * descriptors passed via provideFd API. + * + * After this call returns, the file descriptors will likely be closed by + * the calling client. + * + * @return SUCCESS iff IOffloadManager has stopped using all file + * descriptors + * FAIL_TRY_AGAIN if IOffloadManager needs more time with these + * file descriptors before it can release them + * + * Remarks: Currently, it would be very difficult to handle a FAIL_TRY_AGAIN + * because HAL serivce does not own a thread outside of RPC + * Threadpool to reschedule this call. + */ + virtual RET clearAllFds() = 0; + /** + * Query whether STA+AP offload is supported on this device. + * + * @return true if supported, false otherwise + */ + virtual bool isStaApSupported() = 0; + + /* ------------------------------ ROUTE --------------------------------- */ + /** + * Add a downstream prefix that <i>may</i> be forwarded. + * + * The Prefix may be an IPv4 or IPv6 address to signify which family can be + * offloaded from the specified tether interface. If the given IP family, + * as determined by the Prefix, has a corresponding upstream configured, + * then traffic should be forwarded between the two interfaces. + * + * Only traffic that has a downstream address within the specified Prefix + * can be forwarded. Traffic from the same downstream interface that falls + * outside of the Prefix will be unaffected and can be forwarded iff it was + * previously configured via a separate addDownstream call. + * + * If no upstream has been configured, then this information must be cached + * so that offload may begin once an upstream is configured. + * + * This API does <b>not</b> replace any previously configured downstreams + * and must be explicitly removed by calling removeDownstream or by clearing + * the entire configuration by calling stopAllOffload. + * + * @return SUCCESS The new information was accepted + * FAIL_TOO_MANY_PREFIXES The hardware has already accepted the max + * number of Prefixes that can be supported. + * If offload is desired on this Prefix then + * another must be removed first. + * FAIL_UNSUPPORTED The hardware cannot forward traffic from this + * downstream interface and will never be able to. + */ + virtual RET addDownstream(const char* /* downstream */, + const Prefix& /* prefix */) = 0; + /** + * Remove a downstream Prefix that forwarding was previously requested for. + * + * The Prefix may be an IPv4 or IPv6 address. Traffic outside of this + * Prefix is not affected. + * + * @return SUCCESS iff forwarding was previously occurring and has been + * stopped + * SUCCESS_NO_OP iff forwarding was not previously occurring and + * therefore no action needed to be taken + */ + virtual RET removeDownstream(const char* /* downstream */, + const Prefix& /* prefix */) = 0; + /** + * Indicate that hardware should forward traffic from any configured + * downstreams to the specified upstream. + * + * When iface is non-null and non-empty and v4Gw is valid, then any + * currently configured or future configured IPv4 downstreams should be + * forwarded to this upstream interface. + * + * When iface is non-null and non-empty and v6Gw is valid, then any + * currently configured or future configured IPv6 downstreams should be + * forwarded to this upstream interface. + * + * @param iface Upstream interface name. Only one is needed because IPv4 + * and IPv6 interface names are required to match. + * @param v4Gw The address of the IPv4 Gateway on the iface + * @param v6Gw The address of one of the IPv6 Gateways on the iface + * + * @return SUCCESS iff the specified configuration was applied + * SUCCESS_DUPLICATE_CONFIG if this configuration <i>exactly</i> + * matches a previously provided + * configuration. This means that no + * action has to be taken, but, the + * configuration was previously accepted + * and applied. + * FAIL_UNSUPPORTED if hardware cannot support forwarding to this + * upstream interface + * + * Remarks: This overrides any previously configured parameters + */ + virtual RET setUpstream(const char* /* iface */, const Prefix& /* v4Gw */, + const Prefix& /* v6Gw */) = 0; + /** + * All traffic must be returned to the software path and all configuration + * (including provided file descriptors) must be forgotten. + * + * @return SUCCESS If all offload was successfully stopped and provided + * file descriptors were released. + * + * Remarks: This can't really fail? + */ + virtual RET stopAllOffload() = 0; + + /* --------------------------- STATS/POLICY ----------------------------- */ + /** + * Instruct hardware to stop forwarding traffic and send a callback after + * limit bytes have been transferred in either direction on this upstream + * interface. + * + * @param upstream Upstream interface name that the limit should apply to + * @param limit Bytes limit that can occur before action should be taken + * + * @return SUCCESS If the limit was successfully applied + * SUCCESS_OPTIMIZED If the limit was sufficiently high to be + * interpreted as "no quota". + * FAIL_HARDWARE If the limit was rejected by the hardware + * FAIL_UNSUPPORTED If metering is not supported on this interface + * FAIL_TRY_AGAIN If this upstream has not been previously + * configured to allow offload + * (via setUpstreamParameters) + */ + virtual RET setQuota(const char* /* upstream */, uint64_t /* limit */) = 0; + /** + * Query for statistics counters in hardware. + * + * This returns an aggregate of all hardware accelerated traffic which + * has occurred on this upstream interface. + * + * @param upstream Interface on which traffic entered/exited + * @param reset Whether hardware counters should reset after returning + * current statistics + * @param ret Output variable where statistics are returned + * + * @return SUCCESS If the statistics were successfully populated in ret and + * were successfully reset if requested. + * FAIL_TRY_AGAIN If the statistics are not currently available but + * may be available later. This may occur during + * a subsystem restart. + * FAIL_UNSUPPORTED If statistics are not supported on this upstream + */ + virtual RET getStats(const char* /* upstream */, bool /* reset */, + OffloadStatistics& /* ret */) = 0; +}; /* IOffloadManager */ +#endif /* _I_OFFLOAD_MANAGER_H_ */ diff --git a/msm8998/hal/inc/IpaEventRelay.h b/msm8998/hal/inc/IpaEventRelay.h new file mode 100644 index 0000000..4541510 --- /dev/null +++ b/msm8998/hal/inc/IpaEventRelay.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _IPA_EVENT_RELAY_H_ +#define _IPA_EVENT_RELAY_H_ +/* External Includes */ +#include <hidl/HidlTransportSupport.h> + +/* HIDL Includes */ +#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h> + +/* Internal Includes */ +#include "IOffloadManager.h" + +/* Namespace pollution avoidance */ +using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback; + + +class IpaEventRelay : public IOffloadManager::IpaEventListener { +public: + IpaEventRelay(const ::android::sp<ITetheringOffloadCallback>& /* cb */); + /* ----------------------- IPA EVENT LISTENER --------------------------- */ + void onOffloadStarted(); + void onOffloadStopped(StoppedReason /* reason */); + void onOffloadSupportAvailable(); + void onLimitReached(); +private: + const ::android::sp<ITetheringOffloadCallback>& mFramework; +}; /* IpaEventRelay */ +#endif /* _IPA_EVENT_RELAY_H_ */
\ No newline at end of file diff --git a/msm8998/hal/inc/LocalLogBuffer.h b/msm8998/hal/inc/LocalLogBuffer.h new file mode 100644 index 0000000..c23ef7d --- /dev/null +++ b/msm8998/hal/inc/LocalLogBuffer.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LOCAL_LOG_BUFFER_H_ +#define _LOCAL_LOG_BUFFER_H_ +/* External Includes */ +#include <deque> +#include <sstream> +#include <string> +#include <sys/types.h> +#include <vector> + +/* Namespace pollution avoidance */ +using ::std::deque; +using ::std::string; +using ::std::stringstream; +using ::std::vector; + + +class LocalLogBuffer { +public: + class FunctionLog { + public: + FunctionLog(string /* funcName */); + FunctionLog(const FunctionLog& /* other */); + void addArg(string /* kw */, string /* arg */); + void addArg(string /* kw */, vector<string> /* args */); + void addArg(string /* kw */, uint64_t /* arg */); + void setResult(bool /* success */, string /* msg */); + void setResult(vector<unsigned int> /* ret */); + void setResult(uint64_t /* rx */, uint64_t /* tx */); + string toString(); + private: + void maybeAddArgsComma(); + const string mName; + bool mArgsProvided; + stringstream mSSArgs; + stringstream mSSReturn; + }; /* FunctionLog */ + LocalLogBuffer(string /* name */, int /* maxLogs */); + void addLog(FunctionLog /* log */); + void toLogcat(); +private: + deque<FunctionLog> mLogs; + const string mName; + const size_t mMaxLogs; +}; /* LocalLogBuffer */ +#endif /* _LOCAL_LOG_BUFFER_H_ */
\ No newline at end of file diff --git a/msm8998/hal/inc/OffloadStatistics.h b/msm8998/hal/inc/OffloadStatistics.h new file mode 100644 index 0000000..226ea72 --- /dev/null +++ b/msm8998/hal/inc/OffloadStatistics.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _OFFLOAD_STATISTICS_H_ +#define _OFFLOAD_STATISTICS_H_ + +#include <string> +#include <sys/types.h> + + +class OffloadStatistics { +public: + uint64_t rx; + uint64_t tx; + + OffloadStatistics(); + OffloadStatistics(std::string /* upstream */); + + uint64_t getTotalRxBytes(); + uint64_t getTotalTxBytes(); +private: + std::string upstream; +}; /* OffloadStatistics */ +#endif /* _OFFLOAD_STATISTICS_H_ */ diff --git a/msm8998/hal/inc/PrefixParser.h b/msm8998/hal/inc/PrefixParser.h new file mode 100644 index 0000000..4682aa5 --- /dev/null +++ b/msm8998/hal/inc/PrefixParser.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _PREFIX_PARSER_H_ +#define _PREFIX_PARSER_H_ + +/* External Includes */ +#include <string.h> +#include <sys/types.h> +#include <vector> + +/* Internal Includes */ +#include "IOffloadManager.h" + +/* Avoiding namespace pollution */ +using IP_FAM = ::IOffloadManager::IP_FAM; +using Prefix = ::IOffloadManager::Prefix; + +using ::std::string; +using ::std::vector; + + +class PrefixParser { +public: + PrefixParser(); + bool add(vector<string> /* in */); + bool add(string /* in */); + bool addV4(vector<string> /* in */); + bool addV4(string /* in */); + bool addV6(vector<string> /* in */); + bool addV6(string /* in */); + int size(); + bool allAreFullyQualified(); + Prefix getFirstPrefix(); + string getLastErrAsStr(); +private: + bool add(string /* in */, IP_FAM /* famHint */); + bool add(vector<string> /* in */, IP_FAM /* famHint */); + static IP_FAM guessIPFamily(string /* in */); + static bool splitIntoAddrAndMask(string /* in */, string& /* addr */, + string& /* mask */); + static int parseSubnetMask(string /* in */, IP_FAM /* famHint */); + static bool parseV4Addr(string /* in */, Prefix& /* out */); + static bool parseV6Addr(string /* in */, Prefix& /* out */); + static bool populateV4Mask(int /* mask */, Prefix& /* out */); + static bool populateV6Mask(int /* mask */, Prefix& /* out */); + static uint32_t createMask(int /* mask */); + static Prefix makeBlankPrefix(IP_FAM /* famHint */); + bool isMaskValid(int /* mask */, IP_FAM /* fam */); + static const uint32_t FULLY_QUALIFIED_MASK = ~0; + vector<Prefix> mPrefixes; + string mLastErr; +}; /* PrefixParser */ +#endif /* _PREFIX_PARSER_H_ */
\ No newline at end of file diff --git a/msm8998/hal/src/CtUpdateAmbassador.cpp b/msm8998/hal/src/CtUpdateAmbassador.cpp new file mode 100644 index 0000000..4843fe2 --- /dev/null +++ b/msm8998/hal/src/CtUpdateAmbassador.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DBG + #define DBG false +#endif /* DBG */ +#define LOG_TAG "IPAHALService/CtUpdateAmbassador" + +/* External Includes */ +#include <arpa/inet.h> +#include <cutils/log.h> + +/* HIDL Includes */ +#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h> + +/* Internal Includes */ +#include "CtUpdateAmbassador.h" + +/* Namespace pollution avoidance */ +using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback; +using ::android::hardware::tetheroffload::control::V1_0::NetworkProtocol; +using HALIpAddrPortPair = ::android::hardware::tetheroffload::control::V1_0::IPv4AddrPortPair; +using HALNatTimeoutUpdate = ::android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate; + +using IpaIpAddrPortPair = ::IOffloadManager::ConntrackTimeoutUpdater::IpAddrPortPair; +using IpaNatTimeoutUpdate = ::IOffloadManager::ConntrackTimeoutUpdater::NatTimeoutUpdate; +using IpaL4Protocol = ::IOffloadManager::ConntrackTimeoutUpdater::L4Protocol; + + +CtUpdateAmbassador::CtUpdateAmbassador( + const ::android::sp<ITetheringOffloadCallback>& cb) : mFramework(cb) { +} /* CtUpdateAmbassador */ + +void CtUpdateAmbassador::updateTimeout(IpaNatTimeoutUpdate in) { + if (DBG) { + ALOGD("updateTimeout(src={%#010X, %#04X}, dest={%#010X, %#04X}, Proto=%d)", + in.src.ipAddr, in.src.port, in.dst.ipAddr, in.dst.port, + in.proto); + } + HALNatTimeoutUpdate out; + if (!translate(in, out)) { + /* Cannot log the input outside of DBG flag because it contains sensitive + * information. This will lead to a two step debug if the information + * cannot be gleaned from IPACM logs. The other option is to improve this + * with the use of our local log. That would likely still be hard to + * instruct testers to collect logs, because, assuming timeout updates + * are numerous, it will overrun the ring quickly. Therefore, the tester + * would have to know the exact moment as issue occurred. Or we make the + * ring massive. This would lead to a significant memory overhead. + * Because of this overhead, we would likely not want to check in a change + * with it and once we provide a debug build for increasing buffer size, + * why not just define the DBG flag? + */ + ALOGE("Failed to translate timeout event :("); + } else { + mFramework->updateTimeout(out); + } +} /* updateTimeout */ + +bool CtUpdateAmbassador::translate(IpaNatTimeoutUpdate in, HALNatTimeoutUpdate &out) { + return translate(in.src, out.src) + && translate(in.dst, out.dst) + && L4ToNetwork(in.proto, out.proto); +} /* translate */ + +bool CtUpdateAmbassador::translate(IpaIpAddrPortPair in, HALIpAddrPortPair& out) { + char ipAddrStr[INET_ADDRSTRLEN]; + + if (inet_ntop(AF_INET, &(in.ipAddr), ipAddrStr, INET_ADDRSTRLEN) == nullptr) { + /* errno would be valid here with EAFNOSUPPORT or ENOSPC, neither should really + * be possible in our scenario though. + */ + return false; + } + + out.addr = ipAddrStr; + out.port = in.port; + + return true; +} /* translate */ + +bool CtUpdateAmbassador::L4ToNetwork(IpaL4Protocol in, NetworkProtocol &out) { + bool ret = false; + switch(in) { + case IpaL4Protocol::TCP: + ret = true; + out = NetworkProtocol::TCP; + break; + case IpaL4Protocol::UDP: + ret = true; + out = NetworkProtocol::UDP; + break; + default: + ret = false; + break; + } + return ret; +} /* L4ToNetwork */ diff --git a/msm8998/hal/src/HAL.cpp b/msm8998/hal/src/HAL.cpp new file mode 100644 index 0000000..0d25aa0 --- /dev/null +++ b/msm8998/hal/src/HAL.cpp @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DBG + #define DBG true +#endif /* DBG */ +#define LOG_TAG "IPAHALService" + +/* HIDL Includes */ +#include <hwbinder/IPCThreadState.h> +#include <hwbinder/ProcessState.h> + +/* Kernel Includes */ +#include <linux/netfilter/nfnetlink_compat.h> + +/* External Includes */ +#include <cutils/log.h> +#include <string> +#include <sys/types.h> +#include <vector> + +/* Internal Includes */ +#include "HAL.h" +#include "LocalLogBuffer.h" +#include "PrefixParser.h" + +/* Namespace pollution avoidance */ +using ::android::hardware::Void; +using ::android::status_t; + +using RET = ::IOffloadManager::RET; +using Prefix = ::IOffloadManager::Prefix; + +using ::std::map; +using ::std::vector; + + +/* ------------------------------ PUBLIC ------------------------------------ */ +HAL* HAL::makeIPAHAL(int version, IOffloadManager* mgr) { + if (DBG) + ALOGI("makeIPAHAL(%d, %s)", version, + (mgr != nullptr) ? "provided" : "null"); + if (nullptr == mgr) return NULL; + else if (version != 1) return NULL; + HAL* ret = new HAL(mgr); + if (nullptr == ret) return NULL; + configureRpcThreadpool(1, false); + ret->registerAsSystemService("ipacm"); + return ret; +} /* makeIPAHAL */ + + +/* ------------------------------ PRIVATE ----------------------------------- */ +HAL::HAL(IOffloadManager* mgr) : mLogs("HAL Function Calls", 50) { + mIPA = mgr; + mCb.clear(); + mCbIpa = nullptr; + mCbCt = nullptr; +} /* HAL */ + +void HAL::registerAsSystemService(const char* name) { + status_t ret = 0; + + ret = IOffloadControl::registerAsService(name); + if (ret != 0) ALOGE("Failed to register IOffloadControl (%d)", ret); + else if (DBG) { + ALOGI("Successfully registered IOffloadControl (%s)", name); + } + + IOffloadConfig::registerAsService(name); + if (ret != 0) ALOGE("Failed to register IOffloadConfig (%d)", ret); + else if (DBG) { + ALOGI("Successfully registered IOffloadConfig (%s)", name); + } +} /* registerAsSystemService */ + +void HAL::doLogcatDump() { + ALOGD("mHandles"); + ALOGD("========"); + /* @TODO This will segfault if they aren't initialized and I don't currently + * care to check for initialization in a function that isn't used anyways + * ALOGD("fd1->%d", mHandle1->data[0]); + * ALOGD("fd2->%d", mHandle2->data[0]); + */ + ALOGD("========"); +} /* doLogcatDump */ + +HAL::BoolResult HAL::makeInputCheckFailure(string customErr) { + BoolResult ret; + ret.success = false; + ret.errMsg = "Failed Input Checks: " + customErr; + return ret; +} /* makeInputCheckFailure */ + +HAL::BoolResult HAL::ipaResultToBoolResult(RET in) { + BoolResult ret; + ret.success = (in >= RET::SUCCESS); + switch (in) { + case RET::FAIL_TOO_MANY_PREFIXES: + ret.errMsg = "Too Many Prefixes Provided"; + break; + case RET::FAIL_UNSUPPORTED: + ret.errMsg = "Unsupported by Hardware"; + break; + case RET::FAIL_INPUT_CHECK: + ret.errMsg = "Failed Input Checks"; + break; + case RET::FAIL_HARDWARE: + ret.errMsg = "Hardware did not accept"; + break; + case RET::FAIL_TRY_AGAIN: + ret.errMsg = "Try Again"; + break; + case RET::SUCCESS: + ret.errMsg = "Successful"; + break; + case RET::SUCCESS_DUPLICATE_CONFIG: + ret.errMsg = "Successful: Was a duplicate configuration"; + break; + case RET::SUCCESS_NO_OP: + ret.errMsg = "Successful: No action needed"; + break; + case RET::SUCCESS_OPTIMIZED: + ret.errMsg = "Successful: Performed optimized version of action"; + break; + default: + ret.errMsg = "Unknown Error"; + break; + } + return ret; +} /* ipaResultToBoolResult */ + +/* This will likely always result in doubling the number of loops the execution + * goes through. Obviously that is suboptimal. But if we first translate + * away from all HIDL specific code, then we can avoid sprinkling HIDL + * dependencies everywhere. + */ +vector<string> HAL::convertHidlStrToStdStr(hidl_vec<hidl_string> in) { + vector<string> ret; + for (size_t i = 0; i < in.size(); i++) { + string add = in[i]; + ret.push_back(add); + } + return ret; +} /* convertHidlStrToStdStr */ + +void HAL::registerEventListeners() { + registerIpaCb(); + registerCtCb(); +} /* registerEventListeners */ + +void HAL::registerIpaCb() { + if (isInitialized() && mCbIpa == nullptr) { + LocalLogBuffer::FunctionLog fl("registerEventListener"); + mCbIpa = new IpaEventRelay(mCb); + mIPA->registerEventListener(mCbIpa); + mLogs.addLog(fl); + } else { + ALOGE("Failed to registerIpaCb (isInitialized()=%s, (mCbIpa == nullptr)=%s)", + isInitialized() ? "true" : "false", + (mCbIpa == nullptr) ? "true" : "false"); + } +} /* registerIpaCb */ + +void HAL::registerCtCb() { + if (isInitialized() && mCbCt == nullptr) { + LocalLogBuffer::FunctionLog fl("registerCtTimeoutUpdater"); + mCbCt = new CtUpdateAmbassador(mCb); + mIPA->registerCtTimeoutUpdater(mCbCt); + mLogs.addLog(fl); + } else { + ALOGE("Failed to registerCtCb (isInitialized()=%s, (mCbCt == nullptr)=%s)", + isInitialized() ? "true" : "false", + (mCbCt == nullptr) ? "true" : "false"); + } +} /* registerCtCb */ + +void HAL::unregisterEventListeners() { + unregisterIpaCb(); + unregisterCtCb(); +} /* unregisterEventListeners */ + +void HAL::unregisterIpaCb() { + if (mCbIpa != nullptr) { + LocalLogBuffer::FunctionLog fl("unregisterEventListener"); + mIPA->unregisterEventListener(mCbIpa); + mCbIpa = nullptr; + mLogs.addLog(fl); + } else { + ALOGE("Failed to unregisterIpaCb"); + } +} /* unregisterIpaCb */ + +void HAL::unregisterCtCb() { + if (mCbCt != nullptr) { + LocalLogBuffer::FunctionLog fl("unregisterCtTimeoutUpdater"); + mIPA->unregisterCtTimeoutUpdater(mCbCt); + mCbCt = nullptr; + mLogs.addLog(fl); + } else { + ALOGE("Failed to unregisterCtCb"); + } +} /* unregisterCtCb */ + +void HAL::clearHandles() { + ALOGI("clearHandles()"); + /* @TODO handle this more gracefully... also remove the log + * + * Things that would be nice, but I can't do: + * [1] Destroy the object (it's on the stack) + * [2] Call freeHandle (it's private) + * + * Things I can do but are hacks: + * [1] Look at code and notice that setTo immediately calls freeHandle + */ + mHandle1.setTo(nullptr, true); + mHandle2.setTo(nullptr, true); +} /* clearHandles */ + +bool HAL::isInitialized() { + return mCb.get() != nullptr; +} /* isInitialized */ + + +/* -------------------------- IOffloadConfig -------------------------------- */ +Return<void> HAL::setHandles( + const hidl_handle &fd1, + const hidl_handle &fd2, + setHandles_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + + if (fd1->numFds != 1) { + BoolResult res = makeInputCheckFailure("Must provide exactly one FD per handle (fd1)"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + + mLogs.addLog(fl); + return Void(); + } + + if (fd2->numFds != 1) { + BoolResult res = makeInputCheckFailure("Must provide exactly one FD per handle (fd2)"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + + mLogs.addLog(fl); + return Void(); + } + + /* The = operator calls freeHandle internally. Therefore, if we were using + * these handles previously, they're now gone... forever. But hopefully the + * new ones kick in very quickly. + * + * After freeing anything previously held, it will dup the FD so we have our + * own copy. + */ + mHandle1 = fd1; + mHandle2 = fd2; + + /* Log the DUPed FD instead of the actual input FD so that we can lookup + * this value in ls -l /proc/<pid>/<fd> + */ + fl.addArg("fd1", mHandle1->data[0]); + fl.addArg("fd2", mHandle2->data[0]); + + /* Try to provide each handle to IPACM. Destroy our DUPed hidl_handles if + * IPACM does not like either input. This keeps us from leaking FDs or + * providing half solutions. + * + * @TODO unfortunately, this does not cover duplicate configs where IPACM + * thinks it is still holding on to a handle that we would have freed above. + * It also probably means that IPACM would not know about the first FD being + * freed if it rejects the second FD. + */ + RET ipaReturn = mIPA->provideFd(mHandle1->data[0], UDP_SUBSCRIPTIONS); + if (ipaReturn == RET::SUCCESS) { + ipaReturn = mIPA->provideFd(mHandle2->data[0], TCP_SUBSCRIPTIONS); + } + + if (ipaReturn != RET::SUCCESS) { + ALOGE("IPACM failed to accept the FDs (%d %d)", mHandle1->data[0], + mHandle2->data[0]); + clearHandles(); + } else { + /* @TODO remove logs after stabilization */ + ALOGI("IPACM was provided two FDs (%d, %d)", mHandle1->data[0], + mHandle2->data[0]); + } + + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + return Void(); +} /* setHandles */ + + +/* -------------------------- IOffloadControl ------------------------------- */ +Return<void> HAL::initOffload +( + const ::android::sp<ITetheringOffloadCallback>& cb, + initOffload_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + + if (isInitialized()) { + BoolResult res = makeInputCheckFailure("Already initialized"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + } else { + /* Should storing the CB be a function? */ + mCb = cb; + registerEventListeners(); + BoolResult res = ipaResultToBoolResult(RET::SUCCESS); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + } + + return Void(); +} /* initOffload */ + +Return<void> HAL::stopOffload +( + stopOffload_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + + if (!isInitialized()) { + BoolResult res = makeInputCheckFailure("Was never initialized"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + } else { + /* Should removing the CB be a function? */ + mCb.clear(); + unregisterEventListeners(); + + RET ipaReturn = mIPA->stopAllOffload(); + if (ipaReturn != RET::SUCCESS) { + /* Ignore IPAs return value here and provide why stopAllOffload + * failed. However, if IPA failed to clearAllFds, then we can't + * clear our map because they may still be in use. + */ + RET ret = mIPA->clearAllFds(); + if (ret == RET::SUCCESS) { + clearHandles(); + } + } else { + ipaReturn = mIPA->clearAllFds(); + /* If IPA fails, they may still be using these for some reason. */ + if (ipaReturn == RET::SUCCESS) { + clearHandles(); + } else { + ALOGE("IPACM failed to return success for clearAllFds so they will not be released..."); + } + } + + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + } + + return Void(); +} /* stopOffload */ + +Return<void> HAL::setLocalPrefixes +( + const hidl_vec<hidl_string>& prefixes, + setLocalPrefixes_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("prefixes", "unused"); + #pragma unused(prefixes) + + /* Fake Success */ + BoolResult res = ipaResultToBoolResult(RET::SUCCESS); + hidl_cb(res.success, res.errMsg); + + fl.setResult(res.success, res.errMsg); + return Void(); +} /* setLocalPrefixes */ + +Return<void> HAL::getForwardedStats +( + const hidl_string& upstream, + getForwardedStats_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("upstream", upstream); + + OffloadStatistics ret; + RET ipaReturn = mIPA->getStats(upstream.c_str(), true, ret); + if (ipaReturn == RET::SUCCESS) { + hidl_cb(ret.getTotalRxBytes(), ret.getTotalTxBytes()); + fl.setResult(ret.getTotalRxBytes(), ret.getTotalTxBytes()); + } else { + /* @TODO Ensure the output is zeroed, but this is probably not enough to + * tell Framework that an error has occurred. If, for example, they had + * not yet polled for statistics previously, they may incorrectly assume + * that simply no statistics have transpired on hardware path. + * + * Maybe ITetheringOffloadCallback:onEvent(OFFLOAD_STOPPED_ERROR) is + * enough to handle this case, time will tell. + */ + hidl_cb(0, 0); + fl.setResult(0, 0); + } + + mLogs.addLog(fl); + return Void(); +} /* getForwardedStats */ + +Return<void> HAL::setDataLimit +( + const hidl_string& upstream, + uint64_t limit, + setDataLimit_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("upstream", upstream); + fl.addArg("limit", limit); + + RET ipaReturn = mIPA->setQuota(upstream.c_str(), limit); + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + + fl.setResult(res.success, res.errMsg); + mLogs.addLog(fl); + return Void(); +} /* setDataLimit */ + +Return<void> HAL::setUpstreamParameters +( + const hidl_string& iface, + const hidl_string& v4Addr, + const hidl_string& v4Gw, + const hidl_vec<hidl_string>& v6Gws, + setUpstreamParameters_cb hidl_cb +) { + vector<string> v6GwStrs = convertHidlStrToStdStr(v6Gws); + + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("iface", iface); + fl.addArg("v4Addr", v4Addr); + fl.addArg("v4Gw", v4Gw); + fl.addArg("v6Gws", v6GwStrs); + + PrefixParser v4AddrParser; + PrefixParser v4GwParser; + PrefixParser v6GwParser; + + /* @TODO maybe we should enforce that these addresses and gateways are fully + * qualified here. But then, how do we allow them to be empty/null as well + * while still preserving a sane API on PrefixParser? + */ + if (!v4AddrParser.addV4(v4Addr) && !v4Addr.empty()) { + BoolResult res = makeInputCheckFailure(v4AddrParser.getLastErrAsStr()); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else if (!v4GwParser.addV4(v4Gw) && !v4Gw.empty()) { + BoolResult res = makeInputCheckFailure(v4GwParser.getLastErrAsStr()); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else if (v6GwStrs.size() >= 1 && !v6GwParser.addV6(v6GwStrs)) { + BoolResult res = makeInputCheckFailure(v6GwParser.getLastErrAsStr()); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else if (v6GwParser.size() > 1) { + RET ipaReturn = mIPA->stopAllOffload(); + if (ipaReturn != RET::SUCCESS) { + BoolResult res = + makeInputCheckFailure("Cannot accept more than 1 IPv6 Gateway. Offload still running and may result in data path errors"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else { + BoolResult res = + makeInputCheckFailure("Cannot accept more than 1 IPv6 Gateway. In an effort to avoid any data path errors, offload has been stopped"); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } + } else { + RET ipaReturn = mIPA->setUpstream( + iface.c_str(), + v4GwParser.getFirstPrefix(), + v6GwParser.getFirstPrefix()); + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } + + mLogs.addLog(fl); + return Void(); +} /* setUpstreamParameters */ + +Return<void> HAL::addDownstream +( + const hidl_string& iface, + const hidl_string& prefix, + addDownstream_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("iface", iface); + fl.addArg("prefix", prefix); + + PrefixParser prefixParser; + + if (!prefixParser.add(prefix)) { + BoolResult res = makeInputCheckFailure(prefixParser.getLastErrAsStr()); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else { + RET ipaReturn = mIPA->addDownstream( + iface.c_str(), + prefixParser.getFirstPrefix()); + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } + + mLogs.addLog(fl); + return Void(); +} /* addDownstream */ + +Return<void> HAL::removeDownstream +( + const hidl_string& iface, + const hidl_string& prefix, + removeDownstream_cb hidl_cb +) { + LocalLogBuffer::FunctionLog fl(__func__); + fl.addArg("iface", iface); + fl.addArg("prefix", prefix); + + PrefixParser prefixParser; + + if (!prefixParser.add(prefix)) { + BoolResult res = makeInputCheckFailure(prefixParser.getLastErrAsStr()); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } else { + RET ipaReturn = mIPA->removeDownstream( + iface.c_str(), + prefixParser.getFirstPrefix()); + BoolResult res = ipaResultToBoolResult(ipaReturn); + hidl_cb(res.success, res.errMsg); + fl.setResult(res.success, res.errMsg); + } + + mLogs.addLog(fl); + return Void(); +} /* removeDownstream */ diff --git a/msm8998/hal/src/IpaEventRelay.cpp b/msm8998/hal/src/IpaEventRelay.cpp new file mode 100644 index 0000000..788b152 --- /dev/null +++ b/msm8998/hal/src/IpaEventRelay.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define LOG_TAG "IPAHALService/IpaEventRelay" +/* External Includes */ +#include <cutils/log.h> + +/* HIDL Includes */ +#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h> + +/* Internal Includes */ +#include "IpaEventRelay.h" + +/* Namespace pollution avoidance */ +using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback; +using ::android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent; + + +IpaEventRelay::IpaEventRelay( + const ::android::sp<ITetheringOffloadCallback>& cb) : mFramework(cb) { +} /* IpaEventRelay */ + +void IpaEventRelay::onOffloadStarted() { + ALOGI("onOffloadStarted()"); + mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STARTED); +} /* onOffloadStarted */ + +void IpaEventRelay::onOffloadStopped(StoppedReason reason) { + ALOGI("onOffloadStopped(%d)", reason); + switch (reason) { + case REQUESTED: + /* + * No way to communicate this to Framework right now, they make an + * assumption that offload is stopped when they remove the + * configuration. + */ + break; + case ERROR: + mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_ERROR); + break; + case UNSUPPORTED: + mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_UNSUPPORTED); + break; + default: + ALOGE("Unknown stopped reason(%d)", reason); + break; + } +} /* onOffloadStopped */ + +void IpaEventRelay::onOffloadSupportAvailable() { + ALOGI("onOffloadSupportAvailable()"); + mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_SUPPORT_AVAILABLE); +} /* onOffloadSupportAvailable */ + +void IpaEventRelay::onLimitReached() { + ALOGI("onLimitReached()"); + mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_LIMIT_REACHED); +} /* onLimitReached */ diff --git a/msm8998/hal/src/LocalLogBuffer.cpp b/msm8998/hal/src/LocalLogBuffer.cpp new file mode 100644 index 0000000..f556e40 --- /dev/null +++ b/msm8998/hal/src/LocalLogBuffer.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define LOG_TAG "IPAHALService/dump" + +/* External Includes */ +#include <cutils/log.h> +#include <deque> +#include <string> +#include <sys/types.h> +#include <vector> + +/* Internal Includes */ +#include "LocalLogBuffer.h" + +/* Namespace pollution avoidance */ +using ::std::deque; +using ::std::string; +using ::std::vector; + + +LocalLogBuffer::FunctionLog::FunctionLog(string funcName) : mName(funcName) { + mArgsProvided = false; +} /* FunctionLog */ + +LocalLogBuffer::FunctionLog::FunctionLog(const FunctionLog& other) : + mName(other.mName) { + mArgsProvided = other.mArgsProvided; + /* Is this right? How do you copy stringstreams without wizardry? */ + mSSArgs.str(other.mSSArgs.str()); + mSSReturn.str(other.mSSReturn.str()); +} /* FunctionLog */ + +void LocalLogBuffer::FunctionLog::addArg(string kw, string arg) { + maybeAddArgsComma(); + mSSArgs << kw << "=" << arg; +} /* addArg */ + +void LocalLogBuffer::FunctionLog::addArg(string kw, vector<string> args) { + maybeAddArgsComma(); + mSSArgs << kw << "=["; + for (size_t i = 0; i < args.size(); i++) { + mSSArgs << args[i]; + if (i < (args.size() - 1)) + mSSArgs << ", "; + } + mSSArgs << "]"; +} /* addArg */ + +void LocalLogBuffer::FunctionLog::addArg(string kw, uint64_t arg) { + maybeAddArgsComma(); + mSSArgs << kw << "=" << arg; +} /* addArg */ + +void LocalLogBuffer::FunctionLog::maybeAddArgsComma() { + if (!mArgsProvided) { + mArgsProvided = true; + } else { + mSSArgs << ", "; + } +} /* maybeAddArgsComma */ + +void LocalLogBuffer::FunctionLog::setResult(bool success, string msg) { + mSSReturn << "[" << ((success) ? "success" : "failure") << ", " << msg + << "]"; +} /* setResult */ + +void LocalLogBuffer::FunctionLog::setResult(vector<unsigned int> ret) { + mSSReturn << "["; + for (size_t i = 0; i < ret.size(); i++) { + mSSReturn << ret[i]; + if (i < (ret.size() - 1)) + mSSReturn << ", "; + } + mSSReturn << "]"; +} /* setResult */ + +void LocalLogBuffer::FunctionLog::setResult(uint64_t rx, uint64_t tx) { + mSSReturn << "[rx=" << rx << ", tx=" << tx << "]"; +} /* setResult */ + +string LocalLogBuffer::FunctionLog::toString() { + stringstream ret; + ret << mName << "(" << mSSArgs.str() << ") returned " << mSSReturn.str(); + return ret.str(); +} /* toString */ + +LocalLogBuffer::LocalLogBuffer(string name, int maxLogs) : mName(name), + mMaxLogs(maxLogs) { +} /* LocalLogBuffer */ + +void LocalLogBuffer::addLog(FunctionLog log) { + while (mLogs.size() > mMaxLogs) + mLogs.pop_front(); + mLogs.push_back(log); +} /* addLog */ + +void LocalLogBuffer::toLogcat() { + for (size_t i = 0; i < mLogs.size(); i++) + ALOGD("%s: %s", mName.c_str(), mLogs[i].toString().c_str()); +} /* toLogcat */ diff --git a/msm8998/hal/src/OffloadStatistics.cpp b/msm8998/hal/src/OffloadStatistics.cpp new file mode 100644 index 0000000..8f8beb6 --- /dev/null +++ b/msm8998/hal/src/OffloadStatistics.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <string.h> +#include <sys/types.h> + +#include "OffloadStatistics.h" + + +/* ------------------------------ PUBLIC ------------------------------------ */ +OffloadStatistics::OffloadStatistics() { + this->upstream = "UNSET"; + this->rx = 0; + this->tx = 0; +} /* OffloadStatistics */ + +OffloadStatistics::OffloadStatistics +( + std::string upstream +) { + this->upstream = upstream; + this->rx = 0; + this->tx =0; +} /* OffloadStatistics */ + +uint64_t OffloadStatistics::getTotalRxBytes() { + return rx; +} /* getTotalRxBytes */ + +uint64_t OffloadStatistics::getTotalTxBytes() { + return tx; +} /* getTotalTxBytes */ diff --git a/msm8998/hal/src/PrefixParser.cpp b/msm8998/hal/src/PrefixParser.cpp new file mode 100644 index 0000000..60aae08 --- /dev/null +++ b/msm8998/hal/src/PrefixParser.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* External Includes */ +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <vector> + +/* Internal Includes */ +#include "IOffloadManager.h" +#include "PrefixParser.h" + +/* Avoiding namespace pollution */ +using IP_FAM = ::IOffloadManager::IP_FAM; +using Prefix = ::IOffloadManager::Prefix; + +using ::std::string; +using ::std::vector; + + +/* ------------------------------ PUBLIC ------------------------------------ */ +PrefixParser::PrefixParser() { + mLastErr = "No Err"; +} /* PrefixParser */ + +bool PrefixParser::add(vector<string> in) { + return add(in, IP_FAM::INVALID); +} /* add */ + +bool PrefixParser::add(string in) { + return add(in, IP_FAM::INVALID); +} /* add */ + +bool PrefixParser::addV4(string in) { + return add(in, IP_FAM::V4); +} /* addV4 */ + +bool PrefixParser::addV4(vector<string> in) { + return add(in, IP_FAM::V4); +} /* addV4 */ + +bool PrefixParser::addV6(string in) { + return add(in, IP_FAM::V6); +} /* addV6 */ + +bool PrefixParser::addV6(vector<string> in) { + for (size_t i = 0; i < in.size(); i++) { + if (!addV6(in[i])) + return false; + } + return true; +} /* addV6 */ + +int PrefixParser::size() { + return mPrefixes.size(); +} /* size */ + +bool PrefixParser::allAreFullyQualified() { + for (size_t i = 0; i < mPrefixes.size(); i++) { + if (mPrefixes[i].fam == IP_FAM::V4) { + uint32_t masked = mPrefixes[i].v4Addr & mPrefixes[i].v4Mask; + if (masked != mPrefixes[i].v4Addr) + return false; + } else { + uint32_t masked[4]; + masked[0] = mPrefixes[i].v6Addr[0] & mPrefixes[i].v6Mask[0]; + masked[1] = mPrefixes[i].v6Addr[1] & mPrefixes[i].v6Mask[1]; + masked[2] = mPrefixes[i].v6Addr[2] & mPrefixes[i].v6Mask[2]; + masked[3] = mPrefixes[i].v6Addr[3] & mPrefixes[i].v6Mask[3]; + for (int j = 0; j < 4; j++) { + if (masked[j] != mPrefixes[i].v6Addr[j]) + return false; + } + } + } + return true; +} /* allAreFullyQualified */ + +Prefix PrefixParser::getFirstPrefix() { + if (size() >= 1) + return mPrefixes[0]; + return makeBlankPrefix(IP_FAM::INVALID); +} /* getFirstPrefix */ + +string PrefixParser::getLastErrAsStr() { + return mLastErr; +} /* getLastErrAsStr */ + + +/* ------------------------------ PRIVATE ----------------------------------- */ +bool PrefixParser::add(vector<string> in, IP_FAM famHint) { + for (size_t i = 0; i < in.size(); i++) { + if (!add(in[i], famHint)) + return false; + } + return true; +} /* add */ + +bool PrefixParser::add(string in, IP_FAM famHint) { + if (famHint == IP_FAM::INVALID) + famHint = guessIPFamily(in); + + string subnet; + string addr; + + if (!splitIntoAddrAndMask(in, addr, subnet)) { + mLastErr = "Failed to split into Address and Mask(" + in + ")"; + return false; + } + + int mask = parseSubnetMask(subnet, famHint); + if (!isMaskValid(mask, famHint)) + return false; + + Prefix pre = makeBlankPrefix(famHint); + + if (famHint == IP_FAM::V4) { + if (!parseV4Addr(addr, pre)) { + mLastErr = "Failed to parse V4 Address(" + addr + ")"; + return false; + } + } else if (!parseV6Addr(addr, pre)) { + mLastErr = "Failed to parse V6 Address(" + addr + ")"; + return false; + } + + if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) { + mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask) + + ", " + addr + ")"; + return false; + } else if (!populateV6Mask(mask, pre)) { + mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask) + + ", " + addr + ")"; + return false; + } + + mPrefixes.push_back(pre); + return true; +} /* add */ + +/* Assumption (based on man inet_pton) + * + * X represents a hex character + * d represents a base 10 digit + * / represents the start of the subnet mask + * (assume that it can be left off of all below combinations) + * + * IPv4 Addresses always look like the following: + * ddd.ddd.ddd.ddd/dd + * + * IPv6 Addresses can look a few different ways: + * x:x:x:x:x:x:x:x/ddd + * x::x/ddd + * x:x:x:x:x:x:d.d.d.d/ddd + * + * Therefore, if a presentation of an IP Address contains a colon, then it + * may not be a valid IPv6, but, it is definitely not valid IPv4. If a + * presentation of an IP Address does not contain a colon, then it may not be + * a valid IPv4, but, it is definitely not IPv6. + */ +IP_FAM PrefixParser::guessIPFamily(string in) { + size_t found = in.find(":"); + if (found != string::npos) + return IP_FAM::V6; + return IP_FAM::V4; +} /* guessIPFamily */ + +bool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) { + size_t pos = in.find("/"); + + if (pos != string::npos && pos >= 1) { + /* addr is now everything up until the first / */ + addr = in.substr(0, pos); + } else if (pos == string::npos) { + /* There is no /, so the entire input is an address */ + addr = in; + } else { + /* There was nothing before the /, not recoverable */ + return false; + } + + if (pos != string::npos && pos < in.size()) { + /* There is a / and it is not the last character. Everything after / + * must be the subnet. + */ + mask = in.substr(pos + 1); + } else if (pos != string::npos && pos == in.size()) { + /* There is a /, but it is the last character. This is garbage, but, + * we may still be able to interpret the address so we will throw it + * out. + */ + mask = ""; + } else if (pos == string::npos) { + /* There is no /, therefore, there is no subnet */ + mask = ""; + } else { + /* This really shouldn't be possible because it would imply that find + * returned a position larger than the size of the input. Just + * preserving sanity that mask is always initialized. + */ + mask = ""; + } + + return true; +} /* splitIntoAddrAndMask */ + +int PrefixParser::parseSubnetMask(string in, IP_FAM famHint) { + if (in.empty()) + /* Treat no subnet mask as fully qualified */ + return (famHint == IP_FAM::V6) ? 128 : 32; + return atoi(in.c_str()); +} /* parseSubnetMask */ + +bool PrefixParser::parseV4Addr(string in, Prefix &out) { + struct sockaddr_in sa; + + int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr)); + + if (ret < 0) { + /* errno would be valid */ + return false; + } else if (ret == 0) { + /* input was not a valid IP address */ + return false; + } + + /* Address in network byte order */ + out.v4Addr = htonl(sa.sin_addr.s_addr); + return true; +} /* parseV4Addr */ + +bool PrefixParser::parseV6Addr(string in, Prefix &out) { + struct sockaddr_in6 sa; + + int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr)); + + if (ret < 0) { + /* errno would be valid */ + return false; + } else if (ret == 0) { + /* input was not a valid IP address */ + return false; + } + + /* Translate unsigned chars to unsigned ints to match IPA + * + * TODO there must be a better way to do this beyond bit fiddling + * Maybe a Union since we've already made the assumption that the data + * structures match? + */ + out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) | + (sa.sin6_addr.s6_addr[1] << 16) | + (sa.sin6_addr.s6_addr[2] << 8) | + (sa.sin6_addr.s6_addr[3]); + out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) | + (sa.sin6_addr.s6_addr[5] << 16) | + (sa.sin6_addr.s6_addr[6] << 8) | + (sa.sin6_addr.s6_addr[7]); + out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) | + (sa.sin6_addr.s6_addr[9] << 16) | + (sa.sin6_addr.s6_addr[10] << 8) | + (sa.sin6_addr.s6_addr[11]); + out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) | + (sa.sin6_addr.s6_addr[13] << 16) | + (sa.sin6_addr.s6_addr[14] << 8) | + (sa.sin6_addr.s6_addr[15]); + return true; +} /* parseV6Addr */ + +bool PrefixParser::populateV4Mask(int mask, Prefix &out) { + if (mask < 0 || mask > 32) + return false; + out.v4Mask = createMask(mask); + return true; +} /* populateV4Mask */ + +bool PrefixParser::populateV6Mask(int mask, Prefix &out) { + if (mask < 0 || mask > 128) + return false; + + for (int i = 0; i < 4; i++) { + out.v6Mask[i] = createMask(mask); + mask = (mask > 32) ? mask - 32 : 0; + } + + return true; +} /* populateV6Mask */ + +uint32_t PrefixParser::createMask(int mask) { + uint32_t ret = 0; + + if (mask >= 32) { + ret = ~ret; + return ret; + } + + for (int i = 0; i < 32; i++) { + if (i < mask) + ret = (ret << 1) | 1; + else + ret = (ret << 1); + } + + return ret; +} /* createMask */ + +Prefix PrefixParser::makeBlankPrefix(IP_FAM famHint) { + Prefix ret; + + ret.fam = famHint; + + ret.v4Addr = 0; + ret.v4Mask = 0; + + ret.v6Addr[0] = 0; + ret.v6Addr[1] = 0; + ret.v6Addr[2] = 0; + ret.v6Addr[3] = 0; + + ret.v6Mask[0] = 0; + ret.v6Mask[1] = 0; + ret.v6Mask[2] = 0; + ret.v6Mask[3] = 0; + + return ret; +} /* makeBlankPrefix */ + +bool PrefixParser::isMaskValid(int mask, IP_FAM fam) { + if (mask < 0) { + mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")"; + return false; + } else if (mask == 0) { + mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")"; + return false; + } else if (fam == IP_FAM::V4 && mask > 32) { + mLastErr = "Interpreted address as V4 but mask was too large(" + + std::to_string(mask) + ")"; + return false; + } else if (fam == IP_FAM::V6 && mask > 128) { + mLastErr = "Interpreted address as V6 but mask was too large(" + + std::to_string(mask) + ")"; + return false; + } + + return true; +} /* isMaskValid */ diff --git a/msm8998/ipacm/inc/IPACM_ConntrackClient.h b/msm8998/ipacm/inc/IPACM_ConntrackClient.h index a6076cf..16d5b9c 100644 --- a/msm8998/ipacm/inc/IPACM_ConntrackClient.h +++ b/msm8998/ipacm/inc/IPACM_ConntrackClient.h @@ -91,6 +91,13 @@ public: static IPACM_ConntrackClient* GetInstance(); + static void UNRegisterWithConnTrack(void); + int fd_tcp; + int fd_udp; + + unsigned int subscrips_tcp; + unsigned int subscrips_udp; + #ifdef IPACM_DEBUG #define iptodot(X,Y) \ IPACMLOG(" %s(0x%x): %d.%d.%d.%d\n", X, Y, ((Y>>24) & 0xFF), ((Y>>16) & 0xFF), ((Y>>8) & 0xFF), (Y & 0xFF)); diff --git a/msm8998/ipacm/inc/IPACM_ConntrackListener.h b/msm8998/ipacm/inc/IPACM_ConntrackListener.h index cdf3ef5..d965cf7 100644 --- a/msm8998/ipacm/inc/IPACM_ConntrackListener.h +++ b/msm8998/ipacm/inc/IPACM_ConntrackListener.h @@ -87,7 +87,6 @@ private: void TriggerWANUp(void *); void TriggerWANDown(uint32_t); int CreateNatThreads(void); - int CreateConnTrackThreads(void); bool AddIface(nat_table_entry *, bool *); void AddORDeleteNatEntry(const nat_entry_bundle *); void PopulateTCPorUDPEntry(struct nf_conntrack *, uint32_t, nat_table_entry *); @@ -116,6 +115,7 @@ public: void HandleNeighIpAddrDelEvt(uint32_t); void HandleSTAClientAddEvt(uint32_t); void HandleSTAClientDelEvt(uint32_t); + int CreateConnTrackThreads(void); }; extern IPACM_ConntrackListener *CtList; diff --git a/msm8998/ipacm/inc/IPACM_Defs.h b/msm8998/ipacm/inc/IPACM_Defs.h index d2cc362..74ed3bf 100644 --- a/msm8998/ipacm/inc/IPACM_Defs.h +++ b/msm8998/ipacm/inc/IPACM_Defs.h @@ -185,6 +185,8 @@ typedef enum IPA_ETH_BRIDGE_CLIENT_DEL, /* ipacm_event_eth_bridge*/ IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, /* ipacm_event_eth_bridge*/ IPA_LAN_DELETE_SELF, /* ipacm_event_data_fid */ + IPA_DOWNSTREAM_ADD, /* ipacm_event_ipahal_stream */ + IPA_DOWNSTREAM_DEL, /* ipacm_event_ipahal_stream */ IPACM_EVENT_MAX } ipa_cm_event_id; @@ -351,4 +353,17 @@ typedef struct _ipacm_ifacemgr_data uint8_t mac_addr[IPA_MAC_ADDR_SIZE]; }ipacm_ifacemgr_data; +typedef struct _ipacm_offload_prefix { + enum ipa_ip_type iptype; + uint32_t v4Addr; + uint32_t v4Mask; + uint32_t v6Addr[4]; + uint32_t v6Mask[4]; +} ipacm_offload_prefix; + +typedef struct { + int if_index; + _ipacm_offload_prefix prefix; +} ipacm_event_ipahal_stream; + #endif /* IPA_CM_DEFS_H */ diff --git a/msm8998/ipacm/inc/IPACM_Lan.h b/msm8998/ipacm/inc/IPACM_Lan.h index 6c54f5e..85ea927 100644 --- a/msm8998/ipacm/inc/IPACM_Lan.h +++ b/msm8998/ipacm/inc/IPACM_Lan.h @@ -224,6 +224,10 @@ protected: uint32_t ipv6_prefix[2]; + bool is_upstream_set[IPA_IP_MAX]; + bool is_downstream_set[IPA_IP_MAX]; + _ipacm_offload_prefix prefix[IPA_IP_MAX]; + private: /* get hdr proc ctx type given source and destination l2 hdr type */ diff --git a/msm8998/ipacm/inc/IPACM_OffloadManager.h b/msm8998/ipacm/inc/IPACM_OffloadManager.h new file mode 100644 index 0000000..85a2063 --- /dev/null +++ b/msm8998/ipacm/inc/IPACM_OffloadManager.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _IPACM_OFFLOAD_MANAGER_H_ +#define _IPACM_OFFLOAD_MANAGER_H_ + + +#include <stdint.h> +#include <IOffloadManager.h> +#include "IPACM_Defs.h" + +using RET = ::IOffloadManager::RET; +using Prefix = ::IOffloadManager::Prefix; +using IP_FAM = ::IOffloadManager::IP_FAM; +using L4Protocol = ::IOffloadManager::ConntrackTimeoutUpdater::L4Protocol; +using natTimeoutUpdate_t = ::IOffloadManager::ConntrackTimeoutUpdater::natTimeoutUpdate_t; +//using ipAddrPortPair_t = ::IOffloadManager::ConntrackTimeoutUpdater::ipAddrPortPair_t; +//using UDP = ::IOffloadManager::ConntrackTimeoutUpdater::UDP; +//using TCP = ::IOffloadManager::ConntrackTimeoutUpdater::TCP; + + + +class IPACM_OffloadManager : public IOffloadManager +{ + +public: + + IPACM_OffloadManager(); + static IPACM_OffloadManager* GetInstance(); + + virtual RET registerEventListener(IpaEventListener* /* listener */); + virtual RET unregisterEventListener(IpaEventListener* /* listener */); + virtual RET registerCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */); + virtual RET unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */); + + virtual RET provideFd(int /* fd */, unsigned int /* group */); + virtual RET clearAllFds(); + virtual bool isStaApSupported(); + + /* ---------------------------- ROUTE ------------------------------- */ + virtual RET setLocalPrefixes(std::vector<Prefix> &/* prefixes */); + virtual RET addDownstream(const char * /* downstream */, + const Prefix & /* prefix */); + virtual RET removeDownstream(const char * /* downstream */, + const Prefix &/* prefix */); + virtual RET setUpstream(const char* /* iface */, const Prefix& /* v4Gw */, const Prefix& /* v6Gw */); + virtual RET stopAllOffload(); + + /* ------------------------- STATS/POLICY --------------------------- */ + virtual RET setQuota(const char * /* upstream */, uint64_t /* limit */); + virtual RET getStats(const char * /* upstream */, bool /* reset */, + OffloadStatistics& /* ret */); + + static IPACM_OffloadManager *pInstance; //sky + + IpaEventListener *elrInstance; + + ConntrackTimeoutUpdater *touInstance; + +private: + + bool upstream_v4_up; + + bool upstream_v6_up; + + int default_gw_index; + + int post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr); + + int ipa_get_if_index(const char *if_name, int *if_index); + + int resetTetherStats(const char *upstream_name); + + static const char *DEVICE_NAME; + +}; /* IPACM_OffloadManager */ + +#endif /* _IPACM_OFFLOAD_MANAGER_H_ */ diff --git a/msm8998/ipacm/inc/IPACM_Wan.h b/msm8998/ipacm/inc/IPACM_Wan.h index fe6d35e..3ed58fe 100644 --- a/msm8998/ipacm/inc/IPACM_Wan.h +++ b/msm8998/ipacm/inc/IPACM_Wan.h @@ -104,6 +104,10 @@ public: static bool isWanUP(int ipa_if_num_tether) { #ifdef FEATURE_IPA_ANDROID +#ifdef FEATURE_IPACM_HAL + return wan_up; +#else + int i; for (i=0; i < ipa_if_num_tether_v4_total;i++) { @@ -116,6 +120,7 @@ public: } } return false; +#endif #else return wan_up; #endif diff --git a/msm8998/ipacm/src/Android.mk b/msm8998/ipacm/src/Android.mk index 4af84c8..26b1ba5 100644 --- a/msm8998/ipacm/src/Android.mk +++ b/msm8998/ipacm/src/Android.mk @@ -12,11 +12,13 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src LOCAL_C_INCLUDES += $(LOCAL_PATH)/../inc LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ipanat/inc +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../hal/inc ifeq ($(call is-platform-sdk-version-at-least,20),true) LOCAL_C_INCLUDES += external/icu/icu4c/source/common else LOCAL_C_INCLUDES += external/icu4c/common endif +#LOCAL_C_INCLUDES += external/dhcpcd LOCAL_C_INCLUDES += external/libxml2/include LOCAL_C_INCLUDES += external/libnetfilter_conntrack/include LOCAL_C_INCLUDES += external/libnfnetlink/include @@ -26,9 +28,9 @@ LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr endif - LOCAL_CFLAGS := -v LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID +LOCAL_CFLAGS += -DFEATURE_IPACM_HAL ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DDEBUG endif @@ -55,15 +57,32 @@ LOCAL_SRC_FILES := IPACM_Main.cpp \ IPACM_Conntrack_NATApp.cpp\ IPACM_ConntrackClient.cpp \ IPACM_ConntrackListener.cpp \ - IPACM_Log.cpp + IPACM_Log.cpp \ + IPACM_OffloadManager.cpp LOCAL_MODULE := ipacm LOCAL_MODULE_TAGS := optional -LOCAL_SHARED_LIBRARIES := libipanat +LOCAL_SHARED_LIBRARIES := liboffloadhal +LOCAL_SHARED_LIBRARIES += libipanat LOCAL_SHARED_LIBRARIES += libxml2 LOCAL_SHARED_LIBRARIES += libnfnetlink LOCAL_SHARED_LIBRARIES += libnetfilter_conntrack +LOCAL_SHARED_LIBRARIES += libhwbinder \ + libhidlbase \ + libhidltransport \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + android.hardware.tetheroffload.config@1.0 \ + android.hardware.tetheroffload.control@1.0 + +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES) + include $(BUILD_EXECUTABLE) ################################################################################ diff --git a/msm8998/ipacm/src/IPACM_ConntrackClient.cpp b/msm8998/ipacm/src/IPACM_ConntrackClient.cpp index 146cedb..8cc3407 100644 --- a/msm8998/ipacm/src/IPACM_ConntrackClient.cpp +++ b/msm8998/ipacm/src/IPACM_ConntrackClient.cpp @@ -60,6 +60,10 @@ IPACM_ConntrackClient::IPACM_ConntrackClient() udp_hdl = NULL; tcp_filter = NULL; udp_filter = NULL; + fd_tcp = -1; + fd_udp = -1; + subscrips_tcp = NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY; + subscrips_udp = NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY; } IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance() @@ -421,10 +425,20 @@ void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *) subscrips |= NF_NETLINK_CONNTRACK_NEW; #endif +#ifdef FEATURE_IPACM_HAL + if (pClient->fd_tcp < 0) { + IPACMERR("unable to get conntrack TCP handle due to fd_tcp is invalid \n"); + return NULL; + } else { + pClient->tcp_hdl = nfct_open2(CONNTRACK, subscrips, pClient->fd_tcp); + } +#else pClient->tcp_hdl = nfct_open(CONNTRACK, subscrips); +#endif + if(pClient->tcp_hdl == NULL) { - PERROR("nfct_open\n"); + PERROR("nfct_open failed on getting tcp_hdl\n"); return NULL; } @@ -475,7 +489,11 @@ void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *) /* de-register the callback */ nfct_callback_unregister(pClient->tcp_hdl); /* close the handle */ +#ifdef FEATURE_IPACM_HAL + nfct_close2(pClient->tcp_hdl, true); +#else nfct_close(pClient->tcp_hdl); +#endif pClient->tcp_hdl = NULL; pthread_exit(NULL); @@ -497,11 +515,21 @@ void* IPACM_ConntrackClient::UDPRegisterWithConnTrack(void *) return NULL; } +#ifdef FEATURE_IPACM_HAL + if (pClient->fd_udp < 0) { + IPACMERR("unable to get conntrack UDP handle due to fd_udp is invalid \n"); + return NULL; + } else { + pClient->udp_hdl = nfct_open2(CONNTRACK, + (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY), pClient->fd_udp); + } +#else pClient->udp_hdl = nfct_open(CONNTRACK, (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)); +#endif if(pClient->udp_hdl == NULL) { - PERROR("nfct_open\n"); + PERROR("nfct_open failed on getting udp_hdl\n"); return NULL; } @@ -551,13 +579,51 @@ ctcatch: /* de-register the callback */ nfct_callback_unregister(pClient->udp_hdl); /* close the handle */ +#ifdef FEATURE_IPACM_HAL + nfct_close2(pClient->udp_hdl, true); +#else nfct_close(pClient->udp_hdl); +#endif pClient->udp_hdl = NULL; pthread_exit(NULL); return NULL; } +/* Thread to initialize TCP Conntrack Filters*/ +void IPACM_ConntrackClient::UNRegisterWithConnTrack(void) +{ + int ret; + IPACM_ConntrackClient *pClient = NULL; + + IPACMDBG("\n"); + + /* destroy the TCP filter.. this will not detach the filter */ + nfct_filter_destroy(pClient->tcp_filter); + pClient->tcp_filter = NULL; + + /* de-register the callback */ + nfct_callback_unregister(pClient->tcp_hdl); + /* close the handle */ + nfct_close(pClient->tcp_hdl); + pClient->tcp_hdl = NULL; + + /* destroy the filter.. this will not detach the filter */ + nfct_filter_destroy(pClient->udp_filter); + pClient->udp_filter = NULL; + + /* de-register the callback */ + nfct_callback_unregister(pClient->udp_hdl); + /* close the handle */ + nfct_close(pClient->udp_hdl); + pClient->udp_hdl = NULL; + + pClient->fd_tcp = 0; + pClient->fd_udp = 0; + + return; +} + void IPACM_ConntrackClient::UpdateUDPFilters(void *param, bool isWan) { static bool isIgnore = false; diff --git a/msm8998/ipacm/src/IPACM_ConntrackListener.cpp b/msm8998/ipacm/src/IPACM_ConntrackListener.cpp index ad3fa1e..de0e7e7 100644 --- a/msm8998/ipacm/src/IPACM_ConntrackListener.cpp +++ b/msm8998/ipacm/src/IPACM_ConntrackListener.cpp @@ -115,9 +115,12 @@ void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt, IPACMDBG_H("Received event: %d with ifname: %s and address: 0x%x\n", evt, ((ipacm_event_iface_up *)data)->ifname, ((ipacm_event_iface_up *)data)->ipv4_addr); - CreateConnTrackThreads(); - IPACM_ConntrackClient::UpdateUDPFilters(data, false); - IPACM_ConntrackClient::UpdateTCPFilters(data, false); + if(isWanUp()) + { + CreateConnTrackThreads(); + IPACM_ConntrackClient::UpdateUDPFilters(data, false); + IPACM_ConntrackClient::UpdateTCPFilters(data, false); + } break; case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT: diff --git a/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp b/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp index f0bdd99..2c06642 100644 --- a/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp +++ b/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp @@ -28,6 +28,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "IPACM_Conntrack_NATApp.h" #include "IPACM_ConntrackClient.h" +#ifdef FEATURE_IPACM_HAL +#include "IPACM_OffloadManager.h" +#endif #define INVALID_IP_ADDR 0x0 @@ -400,11 +403,16 @@ int NatApp::AddEntry(const nat_table_entry *rule) void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts) { int ret; +#ifdef FEATURE_IPACM_HAL + IOffloadManager::ConntrackTimeoutUpdater::natTimeoutUpdate_t entry; + IPACM_OffloadManager* OffloadMng; +#endif iptodot("Private IP:", rule->private_ip); iptodot("Target IP:", rule->target_ip); IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port); +#ifndef FEATURE_IPACM_HAL if(!ct_hdl) { ct_hdl = nfct_open(CONNTRACK, 0); @@ -477,7 +485,47 @@ void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts) rule->timestamp = new_ts; IPACMDBG("Updated time stamp successfully\n"); } +#else + if(rule->protocol == IPPROTO_UDP) + { + entry.proto = IOffloadManager::ConntrackTimeoutUpdater::UDP;; + } + else + { + entry.proto = IOffloadManager::ConntrackTimeoutUpdater::TCP; + } + if(rule->dst_nat == false) + { + entry.src.ipAddr = rule->private_ip; + entry.src.port = rule->private_port; + entry.dst.ipAddr = rule->target_ip; + entry.dst.port = rule->target_port; + IPACMDBG("dst nat is not set\n"); + } + else + { + entry.src.ipAddr = rule->target_ip; + entry.src.port = rule->target_port; + entry.dst.ipAddr = pub_ip_addr; + entry.dst.port = rule->public_port; + IPACMDBG("dst nat is set\n"); + } + + iptodot("Source IP:", entry.src.ipAddr); + iptodot("Destination IP:", entry.dst.ipAddr); + IPACMDBG("Source Port: %d, Destination Port: %d\n", + entry.src.port, entry.dst.port); + + OffloadMng = IPACM_OffloadManager::GetInstance(); + if (OffloadMng->touInstance == NULL) { + IPACMERR("OffloadMng->touInstance is NULL, can't forward to framework!\n"); + } else { + OffloadMng->touInstance->updateTimeout(entry); + IPACMDBG("Updated time stamp successfully\n"); + rule->timestamp = new_ts; + } +#endif return; } diff --git a/msm8998/ipacm/src/IPACM_IfaceManager.cpp b/msm8998/ipacm/src/IPACM_IfaceManager.cpp index a142553..eab43fd 100644 --- a/msm8998/ipacm/src/IPACM_IfaceManager.cpp +++ b/msm8998/ipacm/src/IPACM_IfaceManager.cpp @@ -267,6 +267,10 @@ int IPACM_IfaceManager::create_iface_instance(ipacm_ifacemgr_data *param) IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, lan); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, lan); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, lan); +#ifdef FEATURE_IPACM_HAL + IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_ADD, lan); + IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_DEL, lan); +#endif #else IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, lan); @@ -374,6 +378,10 @@ int IPACM_IfaceManager::create_iface_instance(ipacm_ifacemgr_data *param) IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, wl); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, wl); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, wl); +#ifdef FEATURE_IPACM_HAL + IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_ADD, wl); + IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_DEL, wl); +#endif #else IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl); IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, wl); diff --git a/msm8998/ipacm/src/IPACM_Lan.cpp b/msm8998/ipacm/src/IPACM_Lan.cpp index 991e451..8d853d2 100644 --- a/msm8998/ipacm/src/IPACM_Lan.cpp +++ b/msm8998/ipacm/src/IPACM_Lan.cpp @@ -171,9 +171,17 @@ IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index) /* set the IPA-client pipe enum */ if(ipa_if_cate == LAN_IF) { +#ifdef FEATURE_IPACM_HAL + handle_tethering_client(false, IPACM_CLIENT_MAX); +#else handle_tethering_client(false, IPACM_CLIENT_USB); +#endif } #endif + + memset(is_downstream_set, 0, sizeof(is_downstream_set)); + memset(is_upstream_set, 0, sizeof(is_upstream_set)); + memset(&prefix, 0, sizeof(prefix)); return; } @@ -375,6 +383,9 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) handle_wan_up(IPA_IP_v4); } } + IPACMDBG_H("Finished checking wan_up\n"); + } else { + IPACMDBG_H("Wan_V4 haven't up yet\n"); } if(IPACM_Wan::isWanUP_V6(ipa_if_num)) @@ -393,6 +404,9 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) handle_wan_up(IPA_IP_v6); } } + IPACMDBG_H("Finished checking wan_up_v6\n"); + } else { + IPACMDBG_H("Wan_V6 haven't up yet\n"); } /* Post event to NAT */ @@ -451,20 +465,41 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) + { + IPACMERR("IPA_HANDLE_WAN_UP_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) { - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) +#ifdef FEATURE_IPACM_HAL + if (is_upstream_set[IPA_IP_v4] == false) { - if(data_wan_tether->is_sta == false) + IPACMDBG_H("Add upstream for IPv4.\n"); + is_upstream_set[IPA_IP_v4] = true; + if (is_downstream_set[IPA_IP_v4] == true) { + IPACMDBG_H("Downstream was set before, adding UL rules.\n"); + if (data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); + handle_wan_up_ex(ext_prop, IPA_IP_v4, 0); + } else { + handle_wan_up(IPA_IP_v4); + } + } + } +#else + if (data_wan_tether->is_sta == false) + { ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); handle_wan_up_ex(ext_prop, IPA_IP_v4, 0); - } - else - { + } else { handle_wan_up(IPA_IP_v4); - } } +#endif } break; @@ -472,7 +507,7 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6_TETHER event\n"); data_wan_tether = (ipacm_event_iface_up_tehter*)param; - if(data_wan_tether == NULL) + if (data_wan_tether == NULL) { IPACMERR("No event data is found.\n"); return; @@ -480,13 +515,27 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) + { + IPACMERR("IPA_HANDLE_WAN_UP_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) { - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) +#ifdef FEATURE_IPACM_HAL + if (is_upstream_set[IPA_IP_v6] == false) { + IPACMDBG_H("Add upstream for IPv6.\n"); + is_upstream_set[IPA_IP_v6] = true; + + if (is_downstream_set[IPA_IP_v6] == true) + { + IPACMDBG_H("Downstream was set before, adding UL rules.\n"); memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix)); install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix); - if(data_wan_tether->is_sta == false) + if (data_wan_tether->is_sta == false) { ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); @@ -495,14 +544,24 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) { handle_wan_up(IPA_IP_v6); } + } } +#else + if (data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); + handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); + } else { + handle_wan_up(IPA_IP_v6); + } +#endif } break; case IPA_HANDLE_WAN_DOWN_TETHER: IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_TETHER event\n"); data_wan_tether = (ipacm_event_iface_up_tehter*)param; - if(data_wan_tether == NULL) + if (data_wan_tether == NULL) { IPACMERR("No event data is found.\n"); return; @@ -510,12 +569,29 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) + { + IPACMERR("IPA_HANDLE_WAN_DOWN_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) { - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) +#ifdef FEATURE_IPACM_HAL + if(is_upstream_set[IPA_IP_v4] == true) { - handle_wan_down(data_wan_tether->is_sta); + IPACMDBG_H("Del upstream for IPv4.\n"); + is_upstream_set[IPA_IP_v4] = false; + if(is_downstream_set[IPA_IP_v4] == true) + { + IPACMDBG_H("Downstream was set before, deleting UL rules.\n"); + handle_wan_down(data_wan_tether->is_sta); + } } +#else + handle_wan_down(data_wan_tether->is_sta); +#endif } break; @@ -530,33 +606,116 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) { - /* clean up v6 RT rules*/ - IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER in LAN-instance and need clean up client IPv6 address \n"); + IPACMERR("IPA_HANDLE_WAN_DOWN_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + { +#ifdef FEATURE_IPACM_HAL + if (is_upstream_set[IPA_IP_v6] == true) + { + IPACMDBG_H("Del upstream for IPv6.\n"); + is_upstream_set[IPA_IP_v6] = false; + if(is_downstream_set[IPA_IP_v6] == true) + { + IPACMDBG_H("Downstream was set before, deleting UL rules.\n"); + /* reset usb-client ipv6 rt-rules */ + handle_lan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(data_wan_tether->is_sta); + } + } +#else /* reset usb-client ipv6 rt-rules */ handle_lan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(data_wan_tether->is_sta); +#endif + } + break; - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + case IPA_DOWNSTREAM_ADD: + { + ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param; + ipa_interface_index = iface_ipa_index_query(data->if_index); + if (ipa_interface_index == ipa_if_num) + { + IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n"); + if (is_downstream_set[data->prefix.iptype] == false) { - handle_wan_down_v6(data_wan_tether->is_sta); + IPACMDBG_H("Add downstream for IP iptype %d\n", data->prefix.iptype); + is_downstream_set[data->prefix.iptype] = true; + memcpy(&prefix[data->prefix.iptype], &data->prefix, + sizeof(prefix[data->prefix.iptype])); + + if (is_upstream_set[data->prefix.iptype] == true) + { + IPACMDBG_H("Upstream was set before, adding UL rules.\n"); + if (ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype) + { + if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */ + install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix); + + if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */ + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(data->prefix.iptype); + handle_wan_up_ex(ext_prop, data->prefix.iptype, 0); + } else { + handle_wan_up(data->prefix.iptype); /* STA */ + } + } + } + } else { + IPACMDBG_H("downstream for IP iptype %d already set \n", data->prefix.iptype); } } break; + } + + case IPA_DOWNSTREAM_DEL: + { + ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param; + ipa_interface_index = iface_ipa_index_query(data->if_index); + if (ipa_interface_index == ipa_if_num) + { + IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n"); + if (is_downstream_set[data->prefix.iptype] == true) + { + IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype); + is_downstream_set[data->prefix.iptype] = false; + + if (is_upstream_set[data->prefix.iptype] == true) + { + IPACMDBG_H("Upstream was set before, deleting UL rules.\n"); + if (data->prefix.iptype == IPA_IP_v4) + { + handle_wan_down(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */ + } else { + handle_lan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */ + } + } + } + } + break; + } + #else case IPA_HANDLE_WAN_UP: IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n"); data_wan = (ipacm_event_iface_up*)param; - if(data_wan == NULL) + if (data_wan == NULL) { IPACMERR("No event data is found.\n"); return; } IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta); - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) { - if(data_wan->is_sta == false) + if (data_wan->is_sta == false) { ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); handle_wan_up_ex(ext_prop, IPA_IP_v4, data_wan->xlat_mux_id); @@ -572,17 +731,17 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6 event\n"); data_wan = (ipacm_event_iface_up*)param; - if(data_wan == NULL) + if (data_wan == NULL) { IPACMERR("No event data is found.\n"); return; } IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta); - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) { memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix)); install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix); - if(data_wan->is_sta == false) + if (data_wan->is_sta == false) { ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); @@ -597,13 +756,13 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) case IPA_HANDLE_WAN_DOWN: IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n"); data_wan = (ipacm_event_iface_up*)param; - if(data_wan == NULL) + if (data_wan == NULL) { IPACMERR("No event data is found.\n"); return; } IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta); - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) { handle_wan_down(data_wan->is_sta); } @@ -612,7 +771,7 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) case IPA_HANDLE_WAN_DOWN_V6: IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6 event\n"); data_wan = (ipacm_event_iface_up*)param; - if(data_wan == NULL) + if (data_wan == NULL) { IPACMERR("No event data is found.\n"); return; @@ -623,7 +782,7 @@ void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param) handle_lan_client_reset_rt(IPA_IP_v6); IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta); - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) { handle_wan_down_v6(data_wan->is_sta); } @@ -1267,6 +1426,12 @@ int IPACM_Lan::handle_wan_up(ipa_ip_type ip_type) flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0; flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0; +/* only offload UL traffic of certain clients */ +#ifdef FEATURE_IPACM_HAL + flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR; + flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = prefix[IPA_IP_v4].v4Mask; + flt_rule_entry.rule.attrib.u.v4.dst_addr = prefix[IPA_IP_v4].v4Addr; +#endif memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry)); if (false == m_filtering.AddFilteringRule(m_pFilteringTable)) { @@ -1338,6 +1503,19 @@ int IPACM_Lan::handle_wan_up(ipa_ip_type ip_type) flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000; flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000; +/* only offload UL traffic of certain clients */ +#ifdef FEATURE_IPACM_HAL + flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR; + flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = prefix[IPA_IP_v6].v6Mask[0]; + flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = prefix[IPA_IP_v6].v6Mask[1]; + flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = prefix[IPA_IP_v6].v6Mask[2]; + flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = prefix[IPA_IP_v6].v6Mask[3]; + flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = prefix[IPA_IP_v6].v6Addr[0]; + flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = prefix[IPA_IP_v6].v6Addr[1]; + flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = prefix[IPA_IP_v6].v6Addr[2]; + flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = prefix[IPA_IP_v6].v6Addr[3]; + +#endif memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add)); if (false == m_filtering.AddFilteringRule(m_pFilteringTable)) { @@ -1796,8 +1974,6 @@ int IPACM_Lan::handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptyp uint32_t tx_index; int eth_index,v6_num; const int NUM = 1; - char cmd[200] = {0}; - uint32_t ipv4_addr; if(tx_prop == NULL) { @@ -1875,17 +2051,6 @@ int IPACM_Lan::handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptyp IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n", eth_index, get_client_memptr(eth_client, eth_index)->hdr_hdl_v4); - - /* add static arp entry */ - ipv4_addr = get_client_memptr(eth_client, eth_index)->v4_addr; - snprintf(cmd, sizeof(cmd), "ip neighbor change %d.%d.%d.%d lladdr %02x:%02x:%02x:%02x:%02x:%02x dev %s nud permanent", - (unsigned char)(ipv4_addr >> 24), (unsigned char)(ipv4_addr >> 16), - (unsigned char)(ipv4_addr >> 8), (unsigned char)ipv4_addr, - mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], - dev_name); - IPACMDBG_H("%s\n", cmd); - system(cmd); - strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name)); @@ -2340,8 +2505,6 @@ int IPACM_Lan::handle_eth_client_down_evt(uint8_t *mac_addr) uint32_t tx_index; int num_eth_client_tmp = num_eth_client; int num_v6; - char cmd[200] = {0}; - uint32_t ipv4_addr; IPACMDBG_H("total client: %d\n", num_eth_client_tmp); @@ -2400,13 +2563,6 @@ int IPACM_Lan::handle_eth_client_down_evt(uint8_t *mac_addr) get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false; get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0; - ipv4_addr = get_client_memptr(eth_client, clt_indx)->v4_addr; - snprintf(cmd, sizeof(cmd), "ip neighbor del %d.%d.%d.%d dev %s", - (unsigned char)(ipv4_addr >> 24), (unsigned char)(ipv4_addr >> 16), - (unsigned char)(ipv4_addr >> 8), (unsigned char)ipv4_addr, dev_name); - system(cmd); - IPACMDBG_H("%s\n", cmd); - for (; clt_indx < num_eth_client_tmp - 1; clt_indx++) { memcpy(get_client_memptr(eth_client, clt_indx)->mac, @@ -2472,8 +2628,6 @@ int IPACM_Lan::handle_down_evt() { int i; int res = IPACM_SUCCESS; - char cmd[200] = {0}; - uint32_t ipv4_addr; IPACMDBG_H("lan handle_down_evt\n "); if (ipa_if_cate == ODU_IF) @@ -2656,7 +2810,11 @@ int IPACM_Lan::handle_down_evt() /* reset the IPA-client pipe enum */ if(ipa_if_cate != WAN_IF) { +#ifdef FEATURE_IPACM_HAL + handle_tethering_client(true, IPACM_CLIENT_MAX); +#else handle_tethering_client(true, IPACM_CLIENT_USB); +#endif } #endif /* defined(FEATURE_IPA_ANDROID)*/ fail: @@ -2664,13 +2822,6 @@ fail: IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client); for (i = 0; i < num_eth_client; i++) { - ipv4_addr = get_client_memptr(eth_client, i)->v4_addr; - snprintf(cmd, sizeof(cmd), "ip neighbor del %d.%d.%d.%d dev %s", - (unsigned char)(ipv4_addr >> 24), (unsigned char)(ipv4_addr >> 16), - (unsigned char)(ipv4_addr >> 8), (unsigned char)ipv4_addr, dev_name); - system(cmd); - IPACMDBG_H("%s\n", cmd); - /* First reset nat rules and then route rules */ if(get_client_memptr(eth_client, i)->ipv4_set == true) { @@ -2763,7 +2914,7 @@ int IPACM_Lan::handle_uplink_filter_rule(ipacm_ext_prop *prop, ipa_ip_type iptyp ipa_ioc_add_flt_rule *pFilteringTable; ipa_fltr_installed_notif_req_msg_v01 flt_index; int fd; - int i, index; + int i, index, eq_index; uint32_t value = 0; IPACMDBG_H("Set modem UL flt rules\n"); @@ -2885,6 +3036,73 @@ int IPACM_Lan::handle_uplink_filter_rule(ipacm_ext_prop *prop, ipa_ip_type iptyp IPACMDBG_H("xlat meta-data is modified for rule: %d has index %d with xlat_mux_id: %d\n", cnt, index, xlat_mux_id); } + +#ifdef FEATURE_IPACM_HAL + /* add prefix equation in modem UL rules */ + if(iptype == IPA_IP_v4) + { + flt_rule_entry.rule.eq_attrib.num_offset_meq_32++; + if(flt_rule_entry.rule.eq_attrib.num_offset_meq_32 <= IPA_IPFLTR_NUM_MEQ_32_EQNS) + { + eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_32 - 1; + if(eq_index == 0) + { + flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<5); + } + else + { + flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<6); + } + flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].offset = 12; + flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].mask = prefix[IPA_IP_v4].v4Mask; + flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].value = prefix[IPA_IP_v4].v4Addr; + } + else + { + IPACMERR("Run out of MEQ32 equation.\n"); + flt_rule_entry.rule.eq_attrib.num_offset_meq_32--; + } + } + else + { + flt_rule_entry.rule.eq_attrib.num_offset_meq_128++; + if(flt_rule_entry.rule.eq_attrib.num_offset_meq_128 <= IPA_IPFLTR_NUM_MEQ_128_EQNS) + { + eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_128 - 1; + if(eq_index == 0) + { + flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<3); + } + else + { + flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<4); + } + flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].offset = 8; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 0) + = prefix[IPA_IP_v6].v6Mask[0]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 4) + = prefix[IPA_IP_v6].v6Mask[1]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 8) + = prefix[IPA_IP_v6].v6Mask[2]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 12) + = prefix[IPA_IP_v6].v6Mask[3]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 0) + = prefix[IPA_IP_v6].v6Addr[0]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 4) + = prefix[IPA_IP_v6].v6Addr[1]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 8) + = prefix[IPA_IP_v6].v6Addr[2]; + *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 12) + = prefix[IPA_IP_v6].v6Addr[3]; + } + else + { + IPACMERR("Run out of MEQ128 equation.\n"); + flt_rule_entry.rule.eq_attrib.num_offset_meq_128--; + } + } +#endif + #ifdef FEATURE_IPA_V3 flt_rule_entry.rule.hashable = prop->prop[cnt].is_rule_hashable; flt_rule_entry.rule.rule_id = prop->prop[cnt].rule_id; diff --git a/msm8998/ipacm/src/IPACM_Main.cpp b/msm8998/ipacm/src/IPACM_Main.cpp index c6ab9ee..347bb88 100644 --- a/msm8998/ipacm/src/IPACM_Main.cpp +++ b/msm8998/ipacm/src/IPACM_Main.cpp @@ -68,6 +68,11 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "IPACM_ConntrackClient.h" #include "IPACM_Netlink.h" +#ifdef FEATURE_IPACM_HAL +#include "IPACM_OffloadManager.h" +#include <HAL.h> +#endif + /* not defined(FEATURE_IPA_ANDROID)*/ #ifndef FEATURE_IPA_ANDROID #include "IPACM_LanToLan.h" @@ -78,7 +83,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define IPACM_FIREWALL_FILE_NAME "mobileap_firewall.xml" #define IPACM_CFG_FILE_NAME "IPACM_cfg.xml" #ifdef FEATURE_IPA_ANDROID -#define IPACM_PID_FILE "/data/misc/ipa/ipacm.pid" +#define IPACM_PID_FILE "/data/vendor/misc/ipa/ipacm.pid" #define IPACM_DIR_NAME "/data" #else/* defined(FEATURE_IPA_ANDROID) */ #define IPACM_PID_FILE "/etc/ipacm.pid" @@ -218,6 +223,7 @@ void* ipa_driver_msg_notifier(void *param) struct ipa_wlan_msg_ex *event_ex= NULL; struct ipa_get_data_stats_resp_msg_v01 event_data_stats; struct ipa_get_apn_data_stats_resp_msg_v01 event_network_stats; + IPACM_OffloadManager* OffloadMng; ipacm_cmd_q_data evt_data; ipacm_event_data_mac *data = NULL; @@ -671,7 +677,35 @@ void* ipa_driver_msg_notifier(void *param) evt_data.event = IPA_NETWORK_STATS_UPDATE_EVENT; evt_data.evt_data = data_network_stats; break; - +#ifdef FEATURE_IPACM_HAL + case IPA_QUOTA_REACH: + IPACMDBG_H("Received IPA_QUOTA_REACH\n"); + OffloadMng = IPACM_OffloadManager::GetInstance(); + if (OffloadMng->elrInstance == NULL) { + IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n"); + } else { + OffloadMng->elrInstance->onLimitReached(); + } + break; + case IPA_SSR_BEFORE_SHUTDOWN: + IPACMDBG_H("Received IPA_SSR_BEFORE_SHUTDOWN\n"); + OffloadMng = IPACM_OffloadManager::GetInstance(); + if (OffloadMng->elrInstance == NULL) { + IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n"); + } else { + OffloadMng->elrInstance->onOffloadStopped(IpaEventRelay::ERROR); + } + break; + case IPA_SSR_AFTER_POWERUP: + IPACMDBG_H("Received IPA_SSR_AFTER_POWERUP\n"); + OffloadMng = IPACM_OffloadManager::GetInstance(); + if (OffloadMng->elrInstance == NULL) { + IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n"); + } else { + OffloadMng->elrInstance->onOffloadSupportAvailable(); + } + break; +#endif default: IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type); continue; @@ -733,6 +767,7 @@ int main(int argc, char **argv) int ret; pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0; pthread_t cmd_queue_thread = 0; + IPACM_OffloadManager* OffloadMng; /* check if ipacm is already running or not */ ipa_is_ipacm_running(); @@ -740,12 +775,16 @@ int main(int argc, char **argv) IPACMDBG_H("In main()\n"); IPACM_Neighbor *neigh = new IPACM_Neighbor(); IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager(); +#ifdef FEATURE_IPACM_HAL + OffloadMng = IPACM_OffloadManager::GetInstance(); + HAL *hal = HAL::makeIPAHAL(1, OffloadMng); + IPACMDBG_H(" START IPACM_OffloadManager and link to android framework\n"); +#endif #ifdef FEATURE_ETH_BRIDGE_LE IPACM_LanToLan* lan2lan = new IPACM_LanToLan(); #endif - IPACM_ConntrackClient *cc = IPACM_ConntrackClient::GetInstance(); CtList = new IPACM_ConntrackListener(); IPACMDBG_H("Staring IPA main\n"); diff --git a/msm8998/ipacm/src/IPACM_OffloadManager.cpp b/msm8998/ipacm/src/IPACM_OffloadManager.cpp new file mode 100644 index 0000000..332abd5 --- /dev/null +++ b/msm8998/ipacm/src/IPACM_OffloadManager.cpp @@ -0,0 +1,540 @@ +/* +Copyright (c) 2017, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. +* Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.Z +*/ +/*! + @file + IPACM_OffloadManager.cpp + + @brief + This file implements the basis Iface functionality. + + @Author + Skylar Chang + +*/ +#include <IPACM_OffloadManager.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <string.h> +#include "IPACM_ConntrackClient.h" +#include "IPACM_ConntrackListener.h" +#include "IPACM_Iface.h" +#include "IPACM_Config.h" + +const char *IPACM_OffloadManager::DEVICE_NAME = "/dev/wwan_ioctl"; + +/* NatApp class Implementation */ +IPACM_OffloadManager *IPACM_OffloadManager::pInstance = NULL; + +IPACM_OffloadManager::IPACM_OffloadManager() +{ + default_gw_index = INVALID_IFACE; + upstream_v4_up = false; + upstream_v6_up = false; + return ; +} + +RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener) +{ + RET result = SUCCESS; + if (elrInstance == NULL) + elrInstance = eventlistener; + else { + IPACMDBG_H("already register EventListener previously \n"); + result = FAIL_INPUT_CHECK; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::unregisterEventListener(IpaEventListener* ) +{ + RET result = SUCCESS; + if (elrInstance) + elrInstance = NULL; + else { + IPACMDBG_H("already unregisterEventListener previously \n"); + result = SUCCESS_DUPLICATE_CONFIG; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::registerCtTimeoutUpdater(ConntrackTimeoutUpdater* timeoutupdater) +{ + RET result = SUCCESS; + if (touInstance == NULL) + touInstance = timeoutupdater; + else { + IPACMDBG_H("already register ConntrackTimeoutUpdater previously \n"); + result = FAIL_INPUT_CHECK; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* ) +{ + RET result = SUCCESS; + if (touInstance) + touInstance = NULL; + else { + IPACMDBG_H("already unregisterCtTimeoutUpdater previously \n"); + result = SUCCESS_DUPLICATE_CONFIG; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups) +{ + IPACM_ConntrackClient *cc; + int on = 1, rel; + + cc = IPACM_ConntrackClient::GetInstance(); + + if(!cc) + { + IPACMERR("Init failed: cc %p\n", cc); + return FAIL_HARDWARE; + } + + if (groups == cc->subscrips_tcp) { + cc->fd_tcp = fd; + IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups); + /* set netlink buf */ + rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) ); + if (rel == -1) + { + IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) ); + } + } else if (groups == cc->subscrips_udp) { + cc->fd_udp = fd; + IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups); + /* set netlink buf */ + rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) ); + if (rel == -1) + { + IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) ); + } + } else { + IPACMERR("Received unexpected fd with groups %d.\n", groups); + } + if(cc->fd_tcp >0 && cc->fd_udp >0) { + IPACMDBG_H(" Got both fds from framework, start conntrack listener thread.\n"); + CtList->CreateConnTrackThreads(); + } + return SUCCESS; +} + +RET IPACM_OffloadManager::clearAllFds() +{ + IPACM_ConntrackClient *cc; + + cc = IPACM_ConntrackClient::GetInstance(); + if(!cc) + { + IPACMERR("Init clear: cc %p \n", cc); + return FAIL_HARDWARE; + } + cc->UNRegisterWithConnTrack(); + + return SUCCESS; +} + +bool IPACM_OffloadManager::isStaApSupported() +{ + return true; +} + + +RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */) +{ + return SUCCESS; +} + +RET IPACM_OffloadManager::addDownstream(const char * downstream_name, const Prefix &prefix) +{ + int index; + ipacm_cmd_q_data evt; + ipacm_event_ipahal_stream *evt_data; + + IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam); + if (prefix.fam == V4) { + IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask); + } else { + IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n", + prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]); + IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n", + prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]); + } + + if(ipa_get_if_index(downstream_name, &index)) + { + IPACMERR("fail to get iface index.\n"); + return FAIL_HARDWARE; + } + + evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream)); + if(evt_data == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return FAIL_HARDWARE; + } + memset(evt_data, 0, sizeof(*evt_data)); + + evt_data->if_index = index; + memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix)); + + memset(&evt, 0, sizeof(ipacm_cmd_q_data)); + evt.evt_data = (void*)evt_data; + evt.event = IPA_DOWNSTREAM_ADD; + + IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n"); + IPACM_EvtDispatcher::PostEvt(&evt); + + return SUCCESS; +} + +RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix) +{ + int index; + ipacm_cmd_q_data evt; + ipacm_event_ipahal_stream *evt_data; + + IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam); + if(ipa_get_if_index(downstream_name, &index)) + { + IPACMERR("fail to get iface index.\n"); + return FAIL_HARDWARE; + } + + evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream)); + if(evt_data == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return FAIL_HARDWARE; + } + memset(evt_data, 0, sizeof(*evt_data)); + + evt_data->if_index = index; + memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix)); + + memset(&evt, 0, sizeof(ipacm_cmd_q_data)); + evt.evt_data = (void*)evt_data; + evt.event = IPA_DOWNSTREAM_DEL; + + IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n"); + IPACM_EvtDispatcher::PostEvt(&evt); + + return SUCCESS; +} + +RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6) +{ + int index; + ipacm_cmd_q_data evt; + ipacm_event_data_addr *evt_data_addr; + RET result = SUCCESS; + + /* if interface name is NULL, default route is removed */ + IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam); + + if(upstream_name == NULL) + { + if (default_gw_index == INVALID_IFACE) { + IPACMERR("no previous upstream set before\n"); + return FAIL_INPUT_CHECK; + } + + if (gw_addr_v4.fam == V4 && upstream_v4_up == true) { + IPACMDBG_H("clean upstream(%s) for ipv4-fam(%d) upstream_v4_up(%d)\n", upstream_name, gw_addr_v4.fam, upstream_v4_up); + post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4); + upstream_v4_up = false; + } + if (gw_addr_v6.fam == V6 && upstream_v6_up == true) { + IPACMDBG_H("clean upstream(%s) for ipv6-fam(%d) upstream_v6_up(%d)\n", upstream_name, gw_addr_v6.fam, upstream_v6_up); + post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6); + upstream_v6_up = false; + } + default_gw_index = INVALID_IFACE; + } + else + { + if(ipa_get_if_index(upstream_name, &index)) + { + IPACMERR("fail to get iface index.\n"); + return FAIL_INPUT_CHECK; + } + + /* reset the stats when switch from LTE->STA */ + if (index != default_gw_index) { + IPACMDBG_H(" interface switched to %s\n", upstream_name); + if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0) + { + IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n"); + resetTetherStats(upstream_name); + } + } + + if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) { + + if (upstream_v4_up == false) { + IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr); + /* posting route add event for both IPv4 and IPv6 */ + post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4); + upstream_v4_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name); + } + + if (upstream_v6_up == false) { + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]); + post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6); + upstream_v6_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name); + } + } else if (gw_addr_v4.fam == V4 ) { + IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index); + if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) { + /* clean up previous V6 upstream event */ + IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index); + post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6); + upstream_v6_up = false; + } + + if (upstream_v4_up == false) { + IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr); + /* posting route add event for both IPv4 and IPv6 */ + post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4); + upstream_v4_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name); + result = SUCCESS_DUPLICATE_CONFIG; + } + } else if (gw_addr_v6.fam == V6) { + IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index); + if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) { + /* clean up previous V4 upstream event */ + IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index); + post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4); + upstream_v4_up = false; + } + + if (upstream_v6_up == false) { + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]); + post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6); + upstream_v6_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name); + result = SUCCESS_DUPLICATE_CONFIG; + } + } + default_gw_index = index; + IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name); + } + return result; +} + +RET IPACM_OffloadManager::stopAllOffload() +{ + return SUCCESS; +} + +RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */) +{ + wan_ioctl_set_data_quota quota; + int fd = -1; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) + { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + quota.quota_mbytes = mb; + quota.set_quota = true; + + memset(quota.interface_name, 0, IFNAMSIZ); + if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream"); + close(fd); + return FAIL_INPUT_CHECK; + } + + IPACMDBG_H("SET_DATA_QUOTA %s %lld", quota.interface_name, mb); + + if (ioctl(fd, WAN_IOC_SET_DATA_QUOTA, "a) < 0) { + IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s", strerror(errno)); + close(fd); + return FAIL_TRY_AGAIN; + } + + close(fd); + return SUCCESS; +} + +RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */, + bool reset /* reset */, OffloadStatistics& offload_stats/* ret */) +{ + int fd = -1; + wan_ioctl_query_tether_stats_all stats; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + memset(&stats, 0, sizeof(stats)); + if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream\n"); + close(fd); + return FAIL_INPUT_CHECK; + } + stats.reset_stats = reset; + stats.ipa_client = IPACM_CLIENT_MAX; + + if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) { + IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno)); + close(fd); + return FAIL_TRY_AGAIN; + } + /* feedback to IPAHAL*/ + offload_stats.tx = stats.tx_bytes; + offload_stats.rx = stats.rx_bytes; + + IPACMDBG_H("send getStats tx:%lld rx:%lld \n", offload_stats.tx, offload_stats.rx); + return SUCCESS; +} + +int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr) +{ + ipacm_cmd_q_data evt; + ipacm_event_data_iptype *evt_data_route; + + evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype)); + if(evt_data_route == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return -EFAULT; + } + memset(evt_data_route, 0, sizeof(*evt_data_route)); + + evt_data_route->if_index = index; + evt_data_route->if_index_tether = 0; + evt_data_route->iptype = iptype; + +#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN + evt_data_route->ipv4_addr_gw = gw_addr.v4Addr; + evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0]; + evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1]; + evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2]; + evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3]; + IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw); + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + evt_data_route->ipv6_addr_gw[0], evt_data_route->ipv6_addr_gw[1], evt_data_route->ipv6_addr_gw[2], evt_data_route->ipv6_addr_gw[3]); +#endif + IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index, + evt_data_route->if_index_tether, evt_data_route->iptype); + + memset(&evt, 0, sizeof(evt)); + evt.evt_data = (void*)evt_data_route; + evt.event = event; + + IPACM_EvtDispatcher::PostEvt(&evt); + + return 0; +} + +int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index) +{ + int fd; + struct ifreq ifr; + + if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + IPACMERR("get interface index socket create failed \n"); + return IPACM_FAILURE; + } + + if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) { + IPACMERR("interface name overflows: len %d\n", strnlen(if_name, sizeof(if_name))); + close(fd); + return IPACM_FAILURE; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + (void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); + IPACMDBG_H("interface name (%s)\n", if_name); + + if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0) + { + IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name); + close(fd); + return IPACM_FAILURE; + } + + *if_index = ifr.ifr_ifindex; + IPACMDBG_H("Interface netdev index %d\n", *if_index); + close(fd); + return IPACM_SUCCESS; +} + +int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */) +{ + int fd = -1; + wan_ioctl_reset_tether_stats stats; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + memset(stats.upstreamIface, 0, IFNAMSIZ); + if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream\n"); + close(fd); + return FAIL_INPUT_CHECK; + } + stats.reset_stats = true; + + if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) { + IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno)); + close(fd); + return FAIL_HARDWARE; + } + IPACMDBG_H("Reset Interface %s stats\n", upstream_name); + return IPACM_SUCCESS; +} + +IPACM_OffloadManager* IPACM_OffloadManager::GetInstance() +{ + if(pInstance == NULL) + pInstance = new IPACM_OffloadManager(); + + return pInstance; +} diff --git a/msm8998/ipacm/src/IPACM_Wan.cpp b/msm8998/ipacm/src/IPACM_Wan.cpp index 43bffe3..0a52ad5 100644 --- a/msm8998/ipacm/src/IPACM_Wan.cpp +++ b/msm8998/ipacm/src/IPACM_Wan.cpp @@ -714,13 +714,14 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) { ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param; ipa_interface_index = iface_ipa_index_query(data->if_index); +#ifndef FEATURE_IPACM_HAL /* add the check see if tether_iface is valid or not */ if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE) { IPACMERR("UPSTREAM_ROUTE_ADD tether_if(%d), not valid ignore\n", INVALID_IFACE); return; } - +#endif if (ipa_interface_index == ipa_if_num) { IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT (Android) for ip-type (%d)\n", data->iptype); @@ -738,12 +739,16 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) #else IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d)\n", dev_name,data->iptype); #endif - handle_route_add_evt(data->iptype); + handle_route_add_evt(data->iptype); //sky } #ifdef FEATURE_IPA_ANDROID +#ifdef FEATURE_IPACM_HAL + post_wan_up_tether_evt(data->iptype, 0); +#else /* using ipa_if_index, not netdev_index */ post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether)); #endif +#endif } else if ((data->iptype == IPA_IP_v6) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)) { @@ -770,9 +775,13 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) handle_route_add_evt(data->iptype); } #ifdef FEATURE_IPA_ANDROID +#ifdef FEATURE_IPACM_HAL + post_wan_up_tether_evt(data->iptype, 0); +#else /* using ipa_if_index, not netdev_index */ post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether)); #endif +#endif } } else /* double check if current default iface is not itself */ @@ -818,13 +827,14 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) { ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param; ipa_interface_index = iface_ipa_index_query(data->if_index); +#ifndef FEATURE_IPACM_HAL /* add the check see if tether_iface is valid or not */ if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE) { IPACMERR("UPSTREAM_ROUTE_DEL tether_if(%d), not valid ignore\n", INVALID_IFACE); return; } - +#endif if (ipa_interface_index == ipa_if_num) { IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT\n"); @@ -833,6 +843,9 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n"); wan_v4_addr_gw_set = false; #ifdef FEATURE_IPA_ANDROID +#ifdef FEATURE_IPACM_HAL + post_wan_down_tether_evt(data->iptype, 0); +#else /* using ipa_if_index, not netdev_index */ post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether)); /* no any ipv4 tether iface support*/ @@ -842,6 +855,7 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) return; } #endif +#endif if(m_is_sta_mode == Q6_WAN) { del_wan_firewall_rule(IPA_IP_v4); @@ -857,6 +871,10 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) else if ((data->iptype == IPA_IP_v6) && (active_v6 == true)) { #ifdef FEATURE_IPA_ANDROID +#ifdef FEATURE_IPACM_HAL + post_wan_down_tether_evt(data->iptype, 0); +#else + /* using ipa_if_index, not netdev_index */ post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether)); /* no any ipv6 tether iface support*/ @@ -866,6 +884,7 @@ void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param) return; } #endif +#endif if(m_is_sta_mode == Q6_WAN) { del_wan_firewall_rule(IPA_IP_v6); @@ -4291,8 +4310,7 @@ int IPACM_Wan::config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, int IPACM_Wan::handle_down_evt() { int res = IPACM_SUCCESS; - int i, tether_total; - int ipa_if_num_tether_tmp[IPA_MAX_IFACE_ENTRIES]; + int i; IPACMDBG_H(" wan handle_down_evt \n"); @@ -4313,50 +4331,22 @@ int IPACM_Wan::handle_down_evt() /* make sure default routing rules and firewall rules are deleted*/ if (active_v4) { - if (rx_prop != NULL) - { + if (rx_prop != NULL) + { del_dft_firewall_rules(IPA_IP_v4); } handle_route_del_evt(IPA_IP_v4); IPACMDBG_H("Delete default v4 routing rules\n"); -#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN - /* posting wan_down_tether for all lan clients */ - for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++) - { - ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i]; - } - tether_total = IPACM_Wan::ipa_if_num_tether_v4_total; - for (i=0; i < tether_total; i++) - { - post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]); - IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n", i, - IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name); - } -#endif } if (active_v6) { - if (rx_prop != NULL) - { + if (rx_prop != NULL) + { del_dft_firewall_rules(IPA_IP_v6); } handle_route_del_evt(IPA_IP_v6); IPACMDBG_H("Delete default v6 routing rules\n"); -#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN - /* posting wan_down_tether for all lan clients */ - for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++) - { - ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i]; - } - tether_total = IPACM_Wan::ipa_if_num_tether_v6_total; - for (i=0; i < tether_total; i++) - { - post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]); - IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n", i, - IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name); - } -#endif } /* Delete default v4 RT rule */ @@ -4637,7 +4627,7 @@ int IPACM_Wan::handle_down_evt_ex() del_wan_firewall_rule(IPA_IP_v6); install_wan_filtering_rule(false); handle_route_del_evt_ex(IPA_IP_v6); -#ifdef FEATURE_IPA_ANDROID //sky +#ifdef FEATURE_IPA_ANDROID /* posting wan_down_tether for all lan clients */ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++) { diff --git a/msm8998/ipacm/src/IPACM_Wlan.cpp b/msm8998/ipacm/src/IPACM_Wlan.cpp index 2152c4d..b47c5ef 100644 --- a/msm8998/ipacm/src/IPACM_Wlan.cpp +++ b/msm8998/ipacm/src/IPACM_Wlan.cpp @@ -118,7 +118,11 @@ IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index) /* set the IPA-client pipe enum */ if(ipa_if_cate == WLAN_IF) { +#ifdef FEATURE_IPACM_HAL + handle_tethering_client(false, IPACM_CLIENT_MAX); +#else handle_tethering_client(false, IPACM_CLIENT_WLAN); +#endif } #endif return; @@ -279,6 +283,9 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACM_Lan::handle_wan_up(IPA_IP_v4); } } + IPACMDBG_H("Finished checking wan_up\n"); + } else { + IPACMDBG_H("Wan_V4 haven't up yet \n"); } if(IPACM_Wan::isWanUP_V6(ipa_if_num)) @@ -298,9 +305,10 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACM_Lan::handle_wan_up(IPA_IP_v6); } } + IPACMDBG_H("Finished checking wan_up_v6\n"); + } else { + IPACMDBG_H("Wan_V6 haven't up yet \n"); } - - IPACMDBG_H("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n"); /* checking if SW-RT_enable */ if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true) { @@ -325,20 +333,41 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) { - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + IPACMERR("IPA_HANDLE_WAN_UP_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + { +#ifdef FEATURE_IPACM_HAL + if(is_upstream_set[IPA_IP_v4] == false) { - if(data_wan_tether->is_sta == false) - { - ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); - IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4, 0); - } - else + IPACMDBG_H("Add upstream for IPv4.\n"); + is_upstream_set[IPA_IP_v4] = true; + if(is_downstream_set[IPA_IP_v4] == true) { - IPACM_Lan::handle_wan_up(IPA_IP_v4); + IPACMDBG_H("Downstream was set before, adding UL rules.\n"); + if(data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); + handle_wan_up_ex(ext_prop, IPA_IP_v4, 0); + } else { + handle_wan_up(IPA_IP_v4); + } } } +#else + if(data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4); + handle_wan_up_ex(ext_prop, IPA_IP_v4, 0); + } else { + handle_wan_up(IPA_IP_v4); + } +#endif } break; @@ -354,23 +383,48 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) { - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + IPACMERR("IPA_HANDLE_WAN_UP_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + { +#ifdef FEATURE_IPACM_HAL + if(is_upstream_set[IPA_IP_v6] == false) { - memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix)); - install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix); + IPACMDBG_H("Add upstream for IPv6.\n"); + is_upstream_set[IPA_IP_v6] = true; - if(data_wan_tether->is_sta == false) + if(is_downstream_set[IPA_IP_v6] == true) { - ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); - IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); - } - else - { - IPACM_Lan::handle_wan_up(IPA_IP_v6); + IPACMDBG_H("Downstream was set before, adding UL rules.\n"); + memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix)); + install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix); + if(data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); + handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); + } + else + { + handle_wan_up(IPA_IP_v6); + } } } +#else + if(data_wan_tether->is_sta == false) + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6); + handle_wan_up_ex(ext_prop, IPA_IP_v6, 0); + } + else + { + handle_wan_up(IPA_IP_v6); + } +#endif } break; @@ -382,23 +436,37 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACMERR("No event data is found.\n"); return; } + if(rx_prop == NULL) + { + IPACMERR("No rx prop.\n"); + return; + } IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) { - if(data_wan_tether->is_sta == false && wlan_ap_index > 0) - { - IPACMDBG_H("This is not the first AP instance and not STA mode, ignore WAN_DOWN event.\n"); - return; - } - if (rx_prop != NULL) + IPACMERR("IPA_HANDLE_WAN_DOWN_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + { +#ifdef FEATURE_IPACM_HAL + if(is_upstream_set[IPA_IP_v4] == true) { - if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX) + IPACMDBG_H("Del upstream for IPv4.\n"); + is_upstream_set[IPA_IP_v4] = false; + if(is_downstream_set[IPA_IP_v4] == true) { + IPACMDBG_H("Downstream was set before, deleting UL rules.\n"); handle_wan_down(data_wan_tether->is_sta); } } +#else + handle_wan_down(data_wan_tether->is_sta); +#endif } break; @@ -410,25 +478,107 @@ void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param) IPACMERR("No event data is found.\n"); return; } + if(rx_prop == NULL) + { + IPACMERR("No rx prop.\n"); + return; + } IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta, data_wan_tether->if_index_tether, IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name); - if (data_wan_tether->if_index_tether == ipa_if_num) +#ifndef FEATURE_IPACM_HAL + if (data_wan_tether->if_index_tether != ipa_if_num) + { + IPACMERR("IPA_HANDLE_WAN_DOWN_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num); + return; + } +#endif + if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) { - /* clean up v6 RT rules*/ - IPACMDBG_H("Received IPA_WAN_V6_DOWN in WLAN-instance and need clean up client IPv6 address \n"); - /* reset wifi-client ipv6 rt-rules */ +#ifdef FEATURE_IPACM_HAL + if(is_upstream_set[IPA_IP_v6] == true) + { + IPACMDBG_H("Del upstream for IPv6.\n"); + is_upstream_set[IPA_IP_v6] = false; + if(is_downstream_set[IPA_IP_v6] == true) + { + IPACMDBG_H("Downstream was set before, deleting UL rules.\n"); + /* reset usb-client ipv6 rt-rules */ + handle_wlan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(data_wan_tether->is_sta); + } + } +#else + /* reset usb-client ipv6 rt-rules */ handle_wlan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(data_wan_tether->is_sta); +#endif + } + break; + + case IPA_DOWNSTREAM_ADD: + { + ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param; + ipa_interface_index = iface_ipa_index_query(data->if_index); + if(ipa_interface_index == ipa_if_num) + { + IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n"); + if(is_downstream_set[data->prefix.iptype] == false) + { + IPACMDBG_H("Add downstream for IP iptype %d.\n", data->prefix.iptype); + is_downstream_set[data->prefix.iptype] = true; + memcpy(&prefix[data->prefix.iptype], &data->prefix, + sizeof(prefix[data->prefix.iptype])); + + if(is_upstream_set[data->prefix.iptype] == true) + { + IPACMDBG_H("Upstream was set before, adding modem UL rules.\n"); + if(ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype) + { + if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */ + install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix); + + if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */ + { + ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(data->prefix.iptype); + handle_wan_up_ex(ext_prop, data->prefix.iptype, 0); + } else { + handle_wan_up(data->prefix.iptype); /* STA */ + } + } + } + } + } + break; + } - if (rx_prop != NULL) + case IPA_DOWNSTREAM_DEL: + { + ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param; + ipa_interface_index = iface_ipa_index_query(data->if_index); + if(ipa_interface_index == ipa_if_num) + { + IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n"); + if(is_downstream_set[data->prefix.iptype] == true) { - if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX) + IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype); + is_downstream_set[data->prefix.iptype] = false; + + if(is_upstream_set[data->prefix.iptype] == true) { - handle_wan_down_v6(data_wan_tether->is_sta); + IPACMDBG_H("Upstream was set before, deleting UL rules.\n"); + if (data->prefix.iptype == IPA_IP_v4) + { + handle_wan_down(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */ + } else { + handle_wlan_client_reset_rt(IPA_IP_v6); + handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */ + } } } } break; + } #else case IPA_HANDLE_WAN_UP: IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n"); @@ -1671,7 +1821,11 @@ int IPACM_Wlan::handle_down_evt() } } /* reset the IPA-client pipe enum */ +#ifdef FEATURE_IPACM_HAL + handle_tethering_client(true, IPACM_CLIENT_MAX); +#else handle_tethering_client(true, IPACM_CLIENT_WLAN); +#endif #endif /* defined(FEATURE_IPA_ANDROID)*/ fail: diff --git a/msm8998/ipacm/src/IPACM_Xml.cpp b/msm8998/ipacm/src/IPACM_Xml.cpp index 120a638..b81856a 100644 --- a/msm8998/ipacm/src/IPACM_Xml.cpp +++ b/msm8998/ipacm/src/IPACM_Xml.cpp @@ -644,14 +644,11 @@ static int IPACM_firewall_xml_parse_tree memset(content_buf, 0, sizeof(content_buf)); memcpy(content_buf, (void *)content, str_size); content_buf[MAX_XML_STR_LEN-1] = '\0'; - if (content_buf > 0) - { - config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask - = ntohl(inet_addr(content_buf)); - IPACMDBG_H("IPv4 destination subnet mask is: %s \n", content_buf); + config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask + = ntohl(inet_addr(content_buf)); + IPACMDBG_H("IPv4 destination subnet mask is: %s \n", content_buf); } } - } else if (0 == IPACM_util_icmp_string((char*)xml_node->name, IPV4TypeOfService_TAG)) { config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TOS; diff --git a/msm8998/ipanat/src/Android.mk b/msm8998/ipanat/src/Android.mk index 22d9b0e..d95c373 100644 --- a/msm8998/ipanat/src/Android.mk +++ b/msm8998/ipanat/src/Android.mk @@ -17,6 +17,8 @@ endif LOCAL_SRC_FILES := ipa_nat_drv.c \ ipa_nat_drvi.c + +LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64 LOCAL_CFLAGS := -DDEBUG LOCAL_MODULE := libipanat LOCAL_MODULE_TAGS := optional |