Merge e1279f7ef7b7048c22d721b41f99443ad3ebcb06 on remote branch

Change-Id: I1c0ab3c6306747fb479642b6c4eeff97932b8faa
diff --git a/hal/Android.bp b/hal/Android.bp
index f7559b2..1c52dcd 100644
--- a/hal/Android.bp
+++ b/hal/Android.bp
@@ -22,6 +22,7 @@
         "libhardware",
         "android.hardware.tetheroffload.config@1.0",
         "android.hardware.tetheroffload.control@1.0",
+        "android.hardware.tetheroffload.control@1.1",
     ],
     export_include_dirs: ["inc"],
     vendor: true,
diff --git a/hal/inc/CtUpdateAmbassador.h b/hal/inc/CtUpdateAmbassador.h
index d4890f3..ef4c5ee 100644
--- a/hal/inc/CtUpdateAmbassador.h
+++ b/hal/inc/CtUpdateAmbassador.h
@@ -32,13 +32,12 @@
 #include <hidl/HidlTransportSupport.h>
 
 /* HIDL Includes */
-#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h>
+#include <android/hardware/tetheroffload/control/1.1/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;
@@ -50,13 +49,13 @@
 
 class CtUpdateAmbassador : public IOffloadManager::ConntrackTimeoutUpdater {
 public:
-    CtUpdateAmbassador(const ::android::sp<ITetheringOffloadCallback>& /* cb */);
+    CtUpdateAmbassador(const ::android::sp<::android::hardware::tetheroffload::control::V1_0::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;
+    const ::android::sp<::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback>& mFramework;
 }; /* CtUpdateAmbassador */
 #endif /* _CT_UPDATE_AMBASSADOR_H_ */
\ No newline at end of file
diff --git a/hal/inc/HAL.h b/hal/inc/HAL.h
index 92ec135..cbabb1b 100644
--- a/hal/inc/HAL.h
+++ b/hal/inc/HAL.h
@@ -31,7 +31,7 @@
 
 /* HIDL Includes */
 #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
-#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
+#include <android/hardware/tetheroffload/control/1.1/IOffloadControl.h>
 #include <hidl/HidlTransportSupport.h>
 
 /* External Includes */
@@ -59,10 +59,11 @@
 using ::std::string;
 using ::std::vector;
 
+using namespace android::hardware::tetheroffload::control;
+using ::android::sp;
 using ::android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
-using ::android::hardware::tetheroffload::control::V1_0::IOffloadControl;
-
-using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
+using ::android::hardware::tetheroffload::control::V1_1::IOffloadControl;
+using ::android::hardware::tetheroffload::control::V1_1::ITetheringOffloadCallback;
 
 #define KERNEL_PAGE 4096
 
@@ -131,9 +132,9 @@
             const hidl_handle& /* fd2 */,
             setHandles_cb /* hidl_cb */);
 
-    /* IOffloadControl */
+    /* IOffloadControl 1.0 */
     Return<void> initOffload(
-            const ::android::sp<ITetheringOffloadCallback>& /* cb */,
+            const ::android::sp<::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback>& /* cb */,
             initOffload_cb /* hidl_cb */);
     Return<void> stopOffload(
             stopOffload_cb /* hidl_cb */);
@@ -161,6 +162,12 @@
             const hidl_string& /* iface */,
             const hidl_string& /* prefix */,
             removeDownstream_cb /* hidl_cb */);
+    /* IOffloadControl 1.1 */
+    Return<void> setDataWarningAndLimit(
+            const hidl_string& /* upstream */,
+            uint64_t /* warningBytes */,
+            uint64_t /* limitBytes */,
+            setDataWarningAndLimit_cb /* hidl_cb */);
 
 private:
     typedef struct BoolResult {
@@ -193,7 +200,8 @@
     hidl_handle mHandle1;
     hidl_handle mHandle2;
     LocalLogBuffer mLogs;
-    ::android::sp<ITetheringOffloadCallback> mCb;
+    android::sp<V1_0::ITetheringOffloadCallback> mCb;
+    android::sp<V1_1::ITetheringOffloadCallback> mCb_1_1;
     IpaEventRelay *mCbIpa;
     CtUpdateAmbassador *mCbCt;
 }; /* HAL */
diff --git a/hal/inc/IOffloadManager.h b/hal/inc/IOffloadManager.h
index 6a357b3..14edffd 100644
--- a/hal/inc/IOffloadManager.h
+++ b/hal/inc/IOffloadManager.h
@@ -120,6 +120,12 @@
          * tether interface pairs when this callback is called.
          */
         virtual void onLimitReached(){}
+        /**
+         * Called when the warning set via setQuota has expired. It is expected
+         * that limit has not been reached yet.
+         *
+         */
+        virtual void onWarningReached(){}
     }; /* IpaEventListener */
 
     /**
@@ -327,6 +333,34 @@
      */
     virtual RET setQuota(const char* /* upstream */, uint64_t /* limit */) = 0;
     /**
+     * This api replaces setQuota.
+     *
+     * Instruct hardware to stop forwarding traffic and send a callback after
+     * warning/limit bytes have been transferred in either direction on this upstream
+     * interface.
+     *
+     * Note that when one of the quota bytes is reached, the other one is still considered valid
+     * unless this method is called again with the same interface.
+     *
+     * @param upstream Upstream interface name that the limit should apply to
+     * @param warningBytes The quota of warning, defined as the number of bytes, starting from
+     *                     zero and counting from now.
+     * @param limitBytes The quota of limit, defined as the number of bytes, starting from zero
+     *                   and counting from now.
+     *
+     * @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 setQuotaWarning(const char* /* upstream */,
+            uint64_t /* warningBytes */,
+            uint64_t /* limitBytes */) = 0;
+    /**
      * Query for statistics counters in hardware.
      *
      * This returns an aggregate of all hardware accelerated traffic which
diff --git a/hal/inc/IpaEventRelay.h b/hal/inc/IpaEventRelay.h
index 4541510..e9acf23 100644
--- a/hal/inc/IpaEventRelay.h
+++ b/hal/inc/IpaEventRelay.h
@@ -32,24 +32,29 @@
 #include <hidl/HidlTransportSupport.h>
 
 /* HIDL Includes */
-#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h>
+#include <android/hardware/tetheroffload/control/1.1/ITetheringOffloadCallback.h>
 
 /* Internal Includes */
 #include "IOffloadManager.h"
 
 /* Namespace pollution avoidance */
-using ::android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
-
+using namespace android::hardware::tetheroffload::control;
+using ::android::hardware::tetheroffload::control::V1_1::OffloadCallbackEvent;
 
 class IpaEventRelay : public IOffloadManager::IpaEventListener {
 public:
-    IpaEventRelay(const ::android::sp<ITetheringOffloadCallback>& /* cb */);
+    IpaEventRelay(const ::android::sp<V1_0::ITetheringOffloadCallback>& /* 1.0 cb */,
+                  const ::android::sp<V1_1::ITetheringOffloadCallback>& /* 1.1 cb */);
     /* ----------------------- IPA EVENT LISTENER --------------------------- */
     void onOffloadStarted();
     void onOffloadStopped(StoppedReason /* reason */);
     void onOffloadSupportAvailable();
     void onLimitReached();
+    void onWarningReached();
 private:
-    const ::android::sp<ITetheringOffloadCallback>& mFramework;
+    const ::android::sp<V1_0::ITetheringOffloadCallback>& mFramework;
+    const ::android::sp<V1_1::ITetheringOffloadCallback>& mFramework_1_1;
+
+    void sendEvent(OffloadCallbackEvent);
 }; /* IpaEventRelay */
 #endif /* _IPA_EVENT_RELAY_H_ */
\ No newline at end of file
diff --git a/hal/src/CtUpdateAmbassador.cpp b/hal/src/CtUpdateAmbassador.cpp
index eba6b93..2ae10f8 100644
--- a/hal/src/CtUpdateAmbassador.cpp
+++ b/hal/src/CtUpdateAmbassador.cpp
@@ -36,7 +36,7 @@
 #include <cutils/log.h>
 
 /* HIDL Includes */
-#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h>
+#include <android/hardware/tetheroffload/control/1.1/ITetheringOffloadCallback.h>
 
 /* Internal Includes */
 #include "CtUpdateAmbassador.h"
diff --git a/hal/src/HAL.cpp b/hal/src/HAL.cpp
index f18767a..a0f3120 100644
--- a/hal/src/HAL.cpp
+++ b/hal/src/HAL.cpp
@@ -60,7 +60,6 @@
 using ::std::map;
 using ::std::vector;
 
-
 /* ------------------------------ PUBLIC ------------------------------------ */
 Return<::android::sp<HAL>> HAL::makeIPAHAL(int version, IOffloadManager* mgr) {
     android::hardware::ProcessState::initWithMmapSize((size_t)(2 * KERNEL_PAGE));
@@ -82,6 +81,7 @@
 HAL::HAL(IOffloadManager* mgr) : mLogs("HAL Function Calls", 50) {
     mIPA = mgr;
     mCb.clear();
+    mCb_1_1.clear();
     mCbIpa = nullptr;
     mCbCt = nullptr;
 } /* HAL */
@@ -180,7 +180,7 @@
 void HAL::registerIpaCb() {
     if (isInitialized() && mCbIpa == nullptr) {
         LocalLogBuffer::FunctionLog fl("registerEventListener");
-        mCbIpa = new IpaEventRelay(mCb);
+        mCbIpa = new IpaEventRelay(mCb, mCb_1_1);
         mIPA->registerEventListener(mCbIpa);
         mLogs.addLog(fl);
     } else {
@@ -193,6 +193,8 @@
 void HAL::registerCtCb() {
     if (isInitialized() && mCbCt == nullptr) {
         LocalLogBuffer::FunctionLog fl("registerCtTimeoutUpdater");
+        // We can allways use the 1.0 callback here since it is always guarenteed to
+        // be non-nullptr if any version is created.
         mCbCt = new CtUpdateAmbassador(mCb);
         mIPA->registerCtTimeoutUpdater(mCbCt);
         mLogs.addLog(fl);
@@ -246,6 +248,7 @@
 } /* clearHandles */
 
 bool HAL::isInitialized() {
+    // Only have to check 1.0 Callback since it will always be created.
     return mCb.get() != nullptr;
 } /* isInitialized */
 
@@ -328,7 +331,7 @@
 /* -------------------------- IOffloadControl ------------------------------- */
 Return<void> HAL::initOffload
 (
-    const ::android::sp<ITetheringOffloadCallback>& cb,
+    const ::android::sp<V1_0::ITetheringOffloadCallback>& cb,
     initOffload_cb hidl_cb
 ) {
     LocalLogBuffer::FunctionLog fl(__func__);
@@ -341,12 +344,21 @@
     } else {
         /* Should storing the CB be a function? */
         mCb = cb;
+        mCb_1_1 = V1_1::ITetheringOffloadCallback::castFrom(cb).withDefault(nullptr);
+        // As long as 1 callback version is supported we are fine.
+        if (mCb == nullptr && mCb_1_1 == nullptr) {
+            BoolResult res = makeInputCheckFailure("callbacks are nullptr");
+            hidl_cb(res.success, res.errMsg);
+            fl.setResult(res.success, res.errMsg);
+            mLogs.addLog(fl);
+        } else {
         registerEventListeners();
         BoolResult res = ipaResultToBoolResult(RET::SUCCESS);
         hidl_cb(res.success, res.errMsg);
         fl.setResult(res.success, res.errMsg);
         mLogs.addLog(fl);
     }
+    }
 
     return Void();
 } /* initOffload */
@@ -365,6 +377,7 @@
     } else {
         /* Should removing the CB be a function? */
         mCb.clear();
+        mCb_1_1.clear();
         unregisterEventListeners();
 
         RET ipaReturn = mIPA->stopAllOffload();
@@ -412,7 +425,7 @@
     memset(&res,0,sizeof(BoolResult));
 
     if (!isInitialized()) {
-        BoolResult res = makeInputCheckFailure("Not initialized");
+        res = makeInputCheckFailure("Not initialized");
     } else if(prefixesStr.size() < 1) {
         res = ipaResultToBoolResult(RET::FAIL_INPUT_CHECK);
     } else if (!parser.add(prefixesStr)) {
@@ -561,7 +574,7 @@
     PrefixParser prefixParser;
 
     if (!isInitialized()) {
-        BoolResult res = makeInputCheckFailure("Not initialized (setUpstreamParameters)");
+        BoolResult res = makeInputCheckFailure("Not initialized (addDownstream)");
         hidl_cb(res.success, res.errMsg);
         fl.setResult(res.success, res.errMsg);
     }
@@ -595,7 +608,7 @@
     PrefixParser prefixParser;
 
     if (!isInitialized()) {
-        BoolResult res = makeInputCheckFailure("Not initialized (setUpstreamParameters)");
+        BoolResult res = makeInputCheckFailure("Not initialized (removeDownstream)");
         hidl_cb(res.success, res.errMsg);
         fl.setResult(res.success, res.errMsg);
     }
@@ -615,3 +628,34 @@
     mLogs.addLog(fl);
     return Void();
 } /* removeDownstream */
+
+Return<void> HAL::setDataWarningAndLimit
+(
+    const hidl_string& upstream,
+    uint64_t warningBytes,
+    uint64_t limitBytes,
+    setDataWarningAndLimit_cb hidl_cb
+) {
+    LocalLogBuffer::FunctionLog fl(__func__);
+    fl.addArg("upstream", upstream);
+    fl.addArg("warningBytes", warningBytes);
+    fl.addArg("limitBytes", limitBytes);
+
+    // Can only be called from HAL 1.1 so no check here is needed.
+    if (!isInitialized()) {
+        BoolResult res = makeInputCheckFailure("Not initialized (setDataWarningAndLimit)");
+        hidl_cb(res.success, res.errMsg);
+        fl.setResult(res.success, res.errMsg);
+    } else {
+        RET ipaReturn = mIPA->setQuotaWarning(upstream.c_str(), limitBytes, warningBytes);
+        if(ipaReturn == RET::FAIL_TRY_AGAIN) {
+            ipaReturn = RET::SUCCESS;
+        }
+        BoolResult res = ipaResultToBoolResult(ipaReturn);
+        hidl_cb(res.success, res.errMsg);
+        fl.setResult(res.success, res.errMsg);
+    }
+
+    mLogs.addLog(fl);
+    return Void();
+} /* setDataWarningAndLimit */
diff --git a/hal/src/IpaEventRelay.cpp b/hal/src/IpaEventRelay.cpp
index 137092f..8eb0570 100644
--- a/hal/src/IpaEventRelay.cpp
+++ b/hal/src/IpaEventRelay.cpp
@@ -29,28 +29,49 @@
 #define LOG_TAG "IPAHALService/IpaEventRelay"
 /* External Includes */
 #include <cutils/log.h>
+//#include <hidl/Status.h> //TODO: Might be easier to return Status
 
 /* HIDL Includes */
-#include <android/hardware/tetheroffload/control/1.0/ITetheringOffloadCallback.h>
+#include <android/hardware/tetheroffload/control/1.1/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;
+using ::android::hardware::Return;
+// using ::android::hardware::Status;
+using ::android::hardware::tetheroffload::control::V1_1::ITetheringOffloadCallback;
 
 
 IpaEventRelay::IpaEventRelay(
-        const ::android::sp<ITetheringOffloadCallback>& cb) : mFramework(cb) {
+        const ::android::sp<V1_0::ITetheringOffloadCallback>& cb,
+        const ::android::sp<V1_1::ITetheringOffloadCallback>& cb_1_1) : mFramework(cb), mFramework_1_1(cb_1_1) {
 } /* IpaEventRelay */
 
+using OnEventVersion = std::function<Return<void>()>;
+void IpaEventRelay::sendEvent(OffloadCallbackEvent event) {
+    // Events need to be sent for the version passed in and all versions defined after that.
+    // This ensures all new versions get the correct events, but vrsion where events where not
+    // defined do not.
+    Return<void> ret;
+    if(mFramework_1_1 != nullptr) {
+        ALOGI("Triggering onEvent_1_1");
+        ret = mFramework_1_1->onEvent_1_1(event);
+    }
+    else { // Fallback to V1_0
+        ALOGI("Triggering onEvent");
+        ret = mFramework->onEvent(
+            (::android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent) event);
+    }
+
+    if (!ret.isOk()) {
+        ALOGE("Triggering onEvent Callback failed.");
+    }
+}
+
 void IpaEventRelay::onOffloadStarted() {
     ALOGI("onOffloadStarted()");
-    auto ret = mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STARTED);
-    if (!ret.isOk()) {
-        ALOGE("Triggering OffloadStarted Callback failed.");
-    }
+    sendEvent(OffloadCallbackEvent::OFFLOAD_STARTED);
 } /* onOffloadStarted */
 
 void IpaEventRelay::onOffloadStopped(StoppedReason reason) {
@@ -63,16 +84,10 @@
          */
     }
     else if ( reason == StoppedReason::ERROR ) {
-        auto ret = mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_ERROR);
-        if (!ret.isOk()) {
-            ALOGE("Triggering OffloadStopped Callback failed.");
-        }
+        sendEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_ERROR);
     }
     else if ( reason == StoppedReason::UNSUPPORTED ) {
-        auto ret = mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_UNSUPPORTED);
-        if (!ret.isOk()) {
-            ALOGE("Triggering OffloadStopped Callback failed.");
-        }
+        sendEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_UNSUPPORTED);
     }
     else {
         ALOGE("Unknown stopped reason(%d)", reason);
@@ -81,16 +96,16 @@
 
 void IpaEventRelay::onOffloadSupportAvailable() {
     ALOGI("onOffloadSupportAvailable()");
-    auto ret = mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_SUPPORT_AVAILABLE);
-    if (!ret.isOk()) {
-        ALOGE("Triggering OffloadSupportAvailable Callback failed.");
-    }
+    sendEvent(OffloadCallbackEvent::OFFLOAD_SUPPORT_AVAILABLE);
 } /* onOffloadSupportAvailable */
 
 void IpaEventRelay::onLimitReached() {
     ALOGI("onLimitReached()");
-    auto ret = mFramework->onEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_LIMIT_REACHED);
-    if (!ret.isOk()) {
-        ALOGE("Triggering LimitReached Callback failed.");
-    }
+    sendEvent(OffloadCallbackEvent::OFFLOAD_STOPPED_LIMIT_REACHED);
 } /* onLimitReached */
+
+/** V1_1 API's **/
+void IpaEventRelay::onWarningReached() {
+    ALOGI("onWarningReached()");
+    sendEvent(OffloadCallbackEvent::OFFLOAD_WARNING_REACHED);
+} /* onWarningReached */
diff --git a/ipacm/Android.bp b/ipacm/Android.bp
index fbb69e3..a237e7c 100644
--- a/ipacm/Android.bp
+++ b/ipacm/Android.bp
@@ -57,6 +57,7 @@
         "libhardware",
         "android.hardware.tetheroffload.config@1.0",
         "android.hardware.tetheroffload.control@1.0",
+        "android.hardware.tetheroffload.control@1.1",
     ],
 }
 
diff --git a/ipacm/inc/IPACM_OffloadManager.h b/ipacm/inc/IPACM_OffloadManager.h
index 8ac904f..146fde8 100644
--- a/ipacm/inc/IPACM_OffloadManager.h
+++ b/ipacm/inc/IPACM_OffloadManager.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, 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
@@ -83,8 +83,10 @@
 
     /* ------------------------- STATS/POLICY --------------------------- */
     virtual RET setQuota(const char * /* upstream */, uint64_t /* limit */);
+    virtual RET setQuotaWarning(const char * /* upstream */,
+	uint64_t /* quota limit */, uint64_t /* warning limit */);
     virtual RET getStats(const char * /* upstream */, bool /* reset */,
-		OffloadStatistics& /* ret */);
+	OffloadStatistics& /* ret */);
 
 	static IPACM_OffloadManager *pInstance;
 
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index d762430..77954c7 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -366,6 +366,8 @@
 	uint8_t netdev_mac[IPA_MAC_ADDR_SIZE];
 	/* create additional set of v4 Coalesce RT-rules: tcp udp */
 	uint32_t dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES+ 2*MAX_DEFAULT_v6_ROUTE_RULES];
+	/* create additional set of v4 low_lat RT-rules: tcp udp */
+	uint32_t dft_low_lat_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+ MAX_DEFAULT_v6_ROUTE_RULES];
 
 	static int num_ipv4_modem_pdn;
 
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
index e559cdf..3e79149 100644
--- a/ipacm/src/IPACM_Filtering.cpp
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -133,7 +133,7 @@
 	for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
 	{
 		IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", cnt,
-				((struct ipa_flt_rule_add_v2  *)&ruleTable->rules)[cnt].rule.attrib.attrib_mask);
+				((struct ipa_flt_rule_add_v2  *)ruleTable->rules)[cnt].rule.attrib.attrib_mask);
 	}
 
 	retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_V2, ruleTable);
@@ -141,7 +141,7 @@
 	{
 		for (cnt = 0; cnt < ruleTable->num_rules; cnt++)
 		{
-			if (((struct ipa_flt_rule_add_v2  *)&ruleTable->rules)[cnt].status != 0)
+			if (((struct ipa_flt_rule_add_v2  *)ruleTable->rules)[cnt].status != 0)
 			{
 				IPACMDBG_H("Adding Filter rule:%d failed with status:%d\n",
 								 cnt, ((struct ipa_flt_rule_add_v2 *)ruleTable->rules)[cnt].status);
@@ -152,7 +152,7 @@
 
 	for (cnt = 0; cnt<ruleTable->num_rules; cnt++)
 	{
-		if (((struct ipa_flt_rule_add_v2  *)&ruleTable->rules)[cnt].status != 0)
+		if (((struct ipa_flt_rule_add_v2  *)ruleTable->rules)[cnt].status != 0)
 		{
 			IPACMERR("Adding Filter rule:%d failed with status:%d\n",
 							 cnt, ((struct ipa_flt_rule_add_v2 *)ruleTable->rules)[cnt].status);
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
index e29289d..8166329 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+Copyright (c) 2013-2021, 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
@@ -783,6 +783,18 @@
 				OffloadMng->elrInstance->onLimitReached();
 			}
 			continue;
+#ifdef IPA_WARNING_LIMIT_EVENT_MAX
+		case IPA_WARNING_LIMIT_REACHED:
+			IPACMDBG_H("Received IPA_WARNING_LIMIT_REACHED\n");
+			OffloadMng = IPACM_OffloadManager::GetInstance();
+			if (OffloadMng->elrInstance == NULL) {
+				IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n");
+			} else {
+				IPACMERR("calling OffloadMng->elrInstance->onWarningReached \n");
+				OffloadMng->elrInstance->onWarningReached();
+			}
+			continue;
+#endif
 		case IPA_SSR_BEFORE_SHUTDOWN:
 			IPACMDBG_H("Received IPA_SSR_BEFORE_SHUTDOWN\n");
 			IPACM_Wan::clearExtProp();
diff --git a/ipacm/src/IPACM_OffloadManager.cpp b/ipacm/src/IPACM_OffloadManager.cpp
index 708725b..2b8012d 100644
--- a/ipacm/src/IPACM_OffloadManager.cpp
+++ b/ipacm/src/IPACM_OffloadManager.cpp
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+Copyright (c) 2017-2021, 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
@@ -651,6 +651,63 @@
 	return SUCCESS;
 }
 
+RET IPACM_OffloadManager::setQuotaWarning(const char * upstream_name /* upstream */,
+uint64_t quota_mb/* quota limit */, uint64_t warning_mb/* warning limit */)
+{
+#ifdef WAN_IOC_SET_DATA_QUOTA_WARNING
+	wan_ioctl_set_data_quota_warning ioctl_data;
+	int fd = -1, rc = 0, err_type = 0;
+
+	if ((fd = open(DEVICE_NAME, O_RDWR)) < 0)
+	{
+		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+		return FAIL_HARDWARE;
+	}
+
+	memset(&ioctl_data, 0, sizeof(ioctl_data));
+
+	if (quota_mb != 0)
+	{
+		ioctl_data.quota_mbytes = quota_mb;
+		ioctl_data.set_quota = true;
+	}
+
+	if (warning_mb != 0)
+	{
+		ioctl_data.warning_mbytes = warning_mb;
+		ioctl_data.set_warning = true;
+	}
+
+
+	if (strlcpy(ioctl_data.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
+		IPACMERR("String truncation occurred on upstream");
+		close(fd);
+		return FAIL_INPUT_CHECK;
+	}
+
+	IPACMDBG_H("SET_DATA_QUOTA_WARNING: Dev: %s, Quota: %llu, Warning: %llu\n",
+		ioctl_data.interface_name, (long long)quota_mb,
+		(long long)warning_mb);
+
+	rc = ioctl(fd, WAN_IOC_SET_DATA_QUOTA_WARNING, &ioctl_data);
+	close(fd);
+	if(rc != 0)
+	{
+		err_type = errno;
+		IPACMERR("IOCTL WAN_IOC_SET_DATA_QUOTA_WARNING call failed: %s err_type: %d\n", strerror(err_type), err_type);
+		if (err_type == ENODEV) {
+			IPACMDBG_H("Invalid argument.\n");
+			return FAIL_UNSUPPORTED;
+		}
+		else {
+			return FAIL_TRY_AGAIN;
+		}
+	}
+#endif
+	return SUCCESS;
+}
+
+
 RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */,
 		bool reset /* reset */, OffloadStatistics& offload_stats/* ret */)
 {
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index c555481..f0aef3c 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -284,9 +284,11 @@
 	struct ipa_flt_rule_add flt_rule_entry;
 	struct ipa_ioc_get_hdr hdr;
 	bool result;
+	int fd_wwan_ioctl = 0;
 
 	const int NUM_RULES = 1;
 	uint32_t num_ipv6_addr;
+	int pipe_idx;
 	int res = IPACM_SUCCESS,len;
 #ifdef FEATURE_IPACM_HAL
 	IPACM_OffloadManager* OffloadMng;
@@ -449,6 +451,40 @@
 			IPACMDBG_H("ipv6 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d) entry %d", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],
 				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable,
 				2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1);
+
+			/* Low latency v6 rule*/
+			fd_wwan_ioctl = open(IPA_DEVICE_NAME, O_RDWR);
+			if(fd_wwan_ioctl < 0)
+			{
+				IPACMDBG_H("Failed to open fd_wwan_ioctl %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+				return false;
+			}
+			pipe_idx = ioctl(fd_wwan_ioctl, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_WAN_LOW_LAT_DATA_CONS);
+			close(fd_wwan_ioctl);
+			if(pipe_idx != -1)
+			{
+				rt_rule_entry->rule.attrib.meta_data = (uint32_t) pipe_idx;
+				/* modem will put pipe-index in meta-data for low-latency traffic with last reserved byte */
+				rt_rule_entry->rule.attrib.meta_data_mask = 0x000000FF;
+				rt_rule_entry->rule.attrib.attrib_mask &= ~IPA_FLT_NEXT_HDR;
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_META_DATA;
+				rt_rule_entry->rule.coalesce = false;
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+					IPACMDBG_H("Routing rule addition failed!\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+				else if (rt_rule_entry->status)
+				{
+						IPACMDBG_H("low lat udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+						res = rt_rule_entry->status;
+						goto fail;
+					}
+					dft_low_lat_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
+					IPACMDBG_H("ipv6 wan iface low lat udp rt-rule hdll=0x%x\n entry %d", dft_low_lat_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + num_dft_rt_v6],
+						MAX_DEFAULT_v4_ROUTE_RULES + num_dft_rt_v6);
+			}
 		}
 		else
 		{
@@ -732,6 +768,39 @@
 			dft_coalesce_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
 			IPACMDBG_H("ipv4 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[1],
 				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
+
+			/* low latency v4 rule*/
+			fd_wwan_ioctl = open(IPA_DEVICE_NAME, O_RDWR);
+			if(fd_wwan_ioctl < 0)
+			{
+				IPACMDBG_H("Failed to open fd_wwan_ioctl %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+				return false;
+			}
+			/* modem will put pipe-index in meta-data for low-latency traffic with last reserved byte */
+			rt_rule_entry->rule.attrib.meta_data = ioctl(fd_wwan_ioctl, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_WAN_LOW_LAT_DATA_CONS);
+			close(fd_wwan_ioctl);
+			if(rt_rule_entry->rule.attrib.meta_data != -1)
+			{
+				rt_rule_entry->rule.attrib.meta_data_mask = 0x000000FF;
+				rt_rule_entry->rule.attrib.attrib_mask &= ~IPA_FLT_PROTOCOL;
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_META_DATA;
+				rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_LOW_LAT_DATA_CONS;
+				rt_rule_entry->rule.coalesce = false;
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMDBG_H("Routing rule addition failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			else if (rt_rule_entry->status)
+			{
+					IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+					res = rt_rule_entry->status;
+					goto fail;
+				}
+				dft_low_lat_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+				IPACMDBG_H("ipv4 low lat udp rt-rule hdll=0x%x\n", dft_low_lat_rt_rule_hdl[0]);
+			}
 		}
 		else
 		{
@@ -5815,6 +5884,13 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+
+		if (m_routing.DeleteRoutingHdl(dft_low_lat_rt_rule_hdl[0], IPA_IP_v4) == false)
+		{
+			IPACMERR("Routing rule low lat deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
 	}
 	else if(ip_type == IPA_IP_v6)
 	{
@@ -5881,6 +5957,16 @@
 				goto fail;
 			}
 		}
+		/* Delete v6 low lat rules */
+		for (i = 0; i < num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_low_lat_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
 	}
 	else
 	{
@@ -5980,6 +6066,13 @@
 			goto fail;
 		}
 
+		if (m_routing.DeleteRoutingHdl(dft_low_lat_rt_rule_hdl[0], IPA_IP_v4) == false)
+		{
+			IPACMERR("Routing rule deletion failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
 		for (i = 0; i < 2*num_dft_rt_v6; i++)
 		{
 			/* delete v6 colasce rules */
@@ -5996,6 +6089,15 @@
 				goto fail;
 			}
 		}
+		for (i = 0; i < num_dft_rt_v6; i++)
+		{
+			if (m_routing.DeleteRoutingHdl(dft_low_lat_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+			{
+				IPACMERR("Routing rule deletion failed!\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+		}
 	}
 
 //	/* check software routing fl rule hdl */
@@ -7446,7 +7548,7 @@
 		rt_rule->num_rules = NUM_RULES;
 		rt_rule->ip = IPA_IP_v4;
 		rt_rule_entry = &rt_rule->rules[0];
-		rt_rule_entry->at_rear = false;
+		rt_rule_entry->at_rear = true;
 		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
 		/* still need setup v4 default routing rule to APPs*/
 		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
@@ -7466,11 +7568,16 @@
 		}
 		rt_rule_entry->rule.hdr_hdl = hdr.hdl;
 		rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
-		/*  default v4 rt-rule */
+
+		/* RSB UDP rule*/
+		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+		rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
 #ifdef IPA_RT_SUPPORT_COAL
+		if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
+			rt_rule_entry->rule.coalesce = true;
+		else
 			rt_rule_entry->rule.coalesce = false;
 #endif
-		/* default v4 rt-rule */
 		if (false == m_routing.AddRoutingRule(rt_rule))
 		{
 			IPACMERR("Routing rule addition failed!\n");
@@ -7479,15 +7586,15 @@
 		}
 		else if (rt_rule_entry->status)
 		{
-			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
 			res = rt_rule_entry->status;
 			goto fail;
 		}
-		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
-		IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
+		dft_coalesce_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("ipv4 wan iface rsb udp rt-rule hdll=0x%x enable(%d)\n", dft_coalesce_rt_rule_hdl[1],
+			IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
 
 		/* RSC TCP rule*/
-		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
 		rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
 #ifdef IPA_RT_SUPPORT_COAL
 		if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
@@ -7511,14 +7618,12 @@
 		IPACMDBG_H("ipv4 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[0],
 			IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
 
-		/* RSB UDP rule*/
-		rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
+		/*  default v4 rt-rule */
+		rt_rule_entry->rule.attrib.attrib_mask &= ~IPA_FLT_PROTOCOL;
 #ifdef IPA_RT_SUPPORT_COAL
-		if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
-			rt_rule_entry->rule.coalesce = true;
-		else
 			rt_rule_entry->rule.coalesce = false;
 #endif
+		/* default v4 rt-rule */
 		if (false == m_routing.AddRoutingRule(rt_rule))
 		{
 			IPACMERR("Routing rule addition failed!\n");
@@ -7527,13 +7632,13 @@
 		}
 		else if (rt_rule_entry->status)
 		{
-			IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
 			res = rt_rule_entry->status;
 			goto fail;
 		}
-		dft_coalesce_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
-		IPACMDBG_H("ipv4 wan iface rsb udp rt-rule hdll=0x%x enable(%d)\n", dft_coalesce_rt_rule_hdl[1],
-			IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
+		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
+
 fail:
 	free(rt_rule);
 	}
@@ -7573,7 +7678,7 @@
 			/* setup same rule for v6_wan table */
 			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
 			rt_rule_entry = &rt_rule->rules[0];
-			rt_rule_entry->at_rear = false;
+			rt_rule_entry->at_rear = true;
 			rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
 			rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = ipv6_addr[i][0];
 			rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = ipv6_addr[i][1];
@@ -7594,7 +7699,58 @@
 			}
 			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
 			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
-			/* legacy default v4 rt-rule */
+
+			/* RSB UDP rule*/
+			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+			rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
+#ifdef IPA_RT_SUPPORT_COAL
+			if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable)
+				rt_rule_entry->rule.coalesce = true;
+			else
+				rt_rule_entry->rule.coalesce = false;
+#endif
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule addition failed!\n");
+				res = IPACM_FAILURE;
+				goto fail2;
+			}
+			else if (rt_rule_entry->status)
+			{
+				IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+				res = rt_rule_entry->status;
+				goto fail2;
+			}
+			dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG_H("ipv6 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1],
+				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
+
+			/* RSC TCP rule*/
+			rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
+#ifdef IPA_RT_SUPPORT_COAL
+			if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
+				rt_rule_entry->rule.coalesce = true;
+			else
+				rt_rule_entry->rule.coalesce = false;
+#endif
+			if (false == m_routing.AddRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule addition failed!\n");
+				res = IPACM_FAILURE;
+				goto fail2;
+			}
+			else if (rt_rule_entry->status)
+			{
+				IPACMERR("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+				res = rt_rule_entry->status;
+				goto fail2;
+			}
+			dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i] = rt_rule_entry->rt_rule_hdl;
+			IPACMDBG_H("ipv6 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i],
+				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
+
+			/* legacy default v6 rt-rule */
+			rt_rule_entry->rule.attrib.attrib_mask &= ~IPA_FLT_NEXT_HDR;
 #ifdef IPA_RT_SUPPORT_COAL
 			rt_rule_entry->rule.coalesce = false;
 #endif
@@ -7633,53 +7789,6 @@
 				dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1],
 				MAX_DEFAULT_v4_ROUTE_RULES + 2*i,
 				MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1);
-			/* RSC TCP rule*/
-			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
-			rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
-#ifdef IPA_RT_SUPPORT_COAL
-			if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
-				rt_rule_entry->rule.coalesce = true;
-			else
-				rt_rule_entry->rule.coalesce = false;
-#endif
-			if (false == m_routing.AddRoutingRule(rt_rule))
-			{
-				IPACMERR("Routing rule addition failed!\n");
-				res = IPACM_FAILURE;
-				goto fail2;
-			}
-			else if (rt_rule_entry->status)
-			{
-				IPACMERR("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
-				res = rt_rule_entry->status;
-				goto fail2;
-			}
-			dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i] = rt_rule_entry->rt_rule_hdl;
-			IPACMDBG_H("ipv6 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i],
-				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
-			/* RSB UDP rule*/
-			rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
-#ifdef IPA_RT_SUPPORT_COAL
-			if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable)
-				rt_rule_entry->rule.coalesce = true;
-			else
-				rt_rule_entry->rule.coalesce = false;
-#endif
-			if (false == m_routing.AddRoutingRule(rt_rule))
-			{
-				IPACMERR("Routing rule addition failed!\n");
-				res = IPACM_FAILURE;
-				goto fail2;
-			}
-			else if (rt_rule_entry->status)
-			{
-				IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
-				res = rt_rule_entry->status;
-				goto fail2;
-			}
-			dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1] = rt_rule_entry->rt_rule_hdl;
-			IPACMDBG_H("ipv6 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1],
-				IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
 		}
 fail2:
 	free(rt_rule);