diff options
Diffstat (limited to 'msm8998/hal')
-rw-r--r-- | msm8998/hal/Android.mk | 29 | ||||
-rw-r--r-- | msm8998/hal/inc/CtUpdateAmbassador.h | 62 | ||||
-rw-r--r-- | msm8998/hal/inc/HAL.h | 199 | ||||
-rw-r--r-- | msm8998/hal/inc/IOffloadManager.h | 350 | ||||
-rw-r--r-- | msm8998/hal/inc/IpaEventRelay.h | 55 | ||||
-rw-r--r-- | msm8998/hal/inc/LocalLogBuffer.h | 73 | ||||
-rw-r--r-- | msm8998/hal/inc/OffloadStatistics.h | 49 | ||||
-rw-r--r-- | msm8998/hal/inc/PrefixParser.h | 79 | ||||
-rw-r--r-- | msm8998/hal/src/CtUpdateAmbassador.cpp | 123 | ||||
-rw-r--r-- | msm8998/hal/src/HAL.cpp | 582 | ||||
-rw-r--r-- | msm8998/hal/src/IpaEventRelay.cpp | 83 | ||||
-rw-r--r-- | msm8998/hal/src/LocalLogBuffer.cpp | 126 | ||||
-rw-r--r-- | msm8998/hal/src/OffloadStatistics.cpp | 57 | ||||
-rw-r--r-- | msm8998/hal/src/PrefixParser.cpp | 375 |
14 files changed, 2242 insertions, 0 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 */ |