diff options
author | Isaac Chen <isaacchen@isaacchen.cn> | 2018-07-13 10:13:25 +0800 |
---|---|---|
committer | Isaac Chen <isaacchen@isaacchen.cn> | 2018-07-13 00:03:17 +0000 |
commit | 2c422cb5c2bd2b93ec56ed970df0051be54f2039 (patch) | |
tree | 2ad31de70b24fbe3dcfe10de8e951b8694aaee9b /data-ipa-cfg-mgr/ipanat/src | |
parent | 6a15b2379f90ba4f9222fea0a5f8c12e8cecbae5 (diff) |
wayne: Import IPACM
* QC Tag: LA.UM.6.2.r1-06100-sdm660.0
Change-Id: I8209c81b5c05f618450248e88226d216935a8bcd
Signed-off-by: Isaac Chen <isaacchen@isaacchen.cn>
Diffstat (limited to 'data-ipa-cfg-mgr/ipanat/src')
-rw-r--r-- | data-ipa-cfg-mgr/ipanat/src/Android.mk | 32 | ||||
-rw-r--r-- | data-ipa-cfg-mgr/ipanat/src/Makefile.am | 38 | ||||
-rw-r--r-- | data-ipa-cfg-mgr/ipanat/src/ipa_nat_drv.c | 215 | ||||
-rw-r--r-- | data-ipa-cfg-mgr/ipanat/src/ipa_nat_drvi.c | 2452 | ||||
-rw-r--r-- | data-ipa-cfg-mgr/ipanat/src/ipa_nat_logi.c | 49 |
5 files changed, 2786 insertions, 0 deletions
diff --git a/data-ipa-cfg-mgr/ipanat/src/Android.mk b/data-ipa-cfg-mgr/ipanat/src/Android.mk new file mode 100644 index 0000000..4e10596 --- /dev/null +++ b/data-ipa-cfg-mgr/ipanat/src/Android.mk @@ -0,0 +1,32 @@ +BOARD_PLATFORM_LIST := msm8909 +BOARD_PLATFORM_LIST += msm8916 +BOARD_PLATFORM_LIST += msm8917 +ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true) +ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM))) +ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH))) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../inc +LOCAL_C_INCLUDES += $(LOCAL_PATH) +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +LOCAL_SRC_FILES := ipa_nat_drv.c \ + ipa_nat_drvi.c + + +LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64 +LOCAL_CFLAGS := -DDEBUG -Wall -Werror +LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID +LOCAL_MODULE := libipanat +LOCAL_MODULE_TAGS := optional +LOCAL_PRELINK_MODULE := false +LOCAL_CLANG := true +include $(BUILD_SHARED_LIBRARY) + +endif # $(TARGET_ARCH) +endif +endif diff --git a/data-ipa-cfg-mgr/ipanat/src/Makefile.am b/data-ipa-cfg-mgr/ipanat/src/Makefile.am new file mode 100644 index 0000000..8e2d005 --- /dev/null +++ b/data-ipa-cfg-mgr/ipanat/src/Makefile.am @@ -0,0 +1,38 @@ +AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs +if KERNELMODULES +AM_CFLAGS += -I./../inc $(KERNEL_DIR)/include +else +AM_CFLAGS += -I./../inc +endif +#AM_CFLAGS += -DDEBUG -g + +common_CFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ +if !KERNELMODULES +common_LDFLAGS = -lrt @GLIB_LIBS@ +endif + +if KERNELMODULES +library_includedir = ../inc $(KERNEL_DIR)/include $(pkgincludedir) +else +library_includedir = $(pkgincludedir) +endif + +c_sources = ipa_nat_drv.c \ + ipa_nat_drvi.c \ + ipa_nat_logi.c + +library_include_HEADERS = ./../inc/ipa_nat_drvi.h \ + ./../inc/ipa_nat_drv.h \ + ./../inc/ipa_nat_logi.h + +if KERNELMODULES +noinst_LIBRARIES = libipanat.a +libipanat_a_C = @C@ +libipanat_a_SOURCES = $(c_sources) +else +lib_LTLIBRARIES = libipanat.la +libipanat_la_C = @C@ +libipanat_la_SOURCES = $(c_sources) +libipanat_la_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) +libipanat_la_LDFLAGS = -shared $(common_LDFLAGS) -version-info 1:0:0 +endif diff --git a/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drv.c b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drv.c new file mode 100644 index 0000000..d01a6c9 --- /dev/null +++ b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drv.c @@ -0,0 +1,215 @@ +/* +Copyright (c) 2013 - 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 "ipa_nat_drv.h" +#include "ipa_nat_drvi.h" + +/** + * ipa_nat_add_ipv4_tbl() - create ipv4 nat table + * @public_ip_addr: [in] public ipv4 address + * @number_of_entries: [in] number of nat entries + * @table_handle: [out] Handle of new ipv4 nat table + * + * To create new ipv4 nat table + * + * Returns: 0 On Success, negative on failure + */ +int ipa_nat_add_ipv4_tbl(uint32_t public_ip_addr, + uint16_t number_of_entries, + uint32_t *tbl_hdl) +{ + int ret; + + if (NULL == tbl_hdl || 0 == number_of_entries) { + IPAERR("Invalid parameters \n"); + return -EINVAL; + } + + ret = ipa_nati_add_ipv4_tbl(public_ip_addr, + number_of_entries, + tbl_hdl); + if (ret != 0) { + IPAERR("unable to add table \n"); + return -EINVAL; + } + IPADBG("Returning table handle 0x%x\n", *tbl_hdl); + + return ret; +} /* __ipa_nat_add_ipv4_tbl() */ + +/** + * ipa_nat_del_ipv4_tbl() - delete ipv4 table + * @table_handle: [in] Handle of ipv4 nat table + * + * To delete given ipv4 nat table + * + * Returns: 0 On Success, negative on failure + */ +int ipa_nat_del_ipv4_tbl(uint32_t tbl_hdl) +{ + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || + tbl_hdl > IPA_NAT_MAX_IP4_TBLS) { + IPAERR("invalid table handle passed \n"); + return -EINVAL; + } + IPADBG("Passed Table Handle: 0x%x\n", tbl_hdl); + + return ipa_nati_del_ipv4_table(tbl_hdl); +} + +/** + * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule + * @table_handle: [in] handle of ipv4 nat table + * @rule: [in] Pointer to new rule + * @rule_handle: [out] Return the handle to rule + * + * To insert new ipv4 nat rule into ipv4 nat table + * + * Returns: 0 On Success, negative on failure + */ +int ipa_nat_add_ipv4_rule(uint32_t tbl_hdl, + const ipa_nat_ipv4_rule *clnt_rule, + uint32_t *rule_hdl) +{ + int result = -EINVAL; + + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || + tbl_hdl > IPA_NAT_MAX_IP4_TBLS || NULL == rule_hdl || + NULL == clnt_rule) { + IPAERR("invalide table handle passed \n"); + return result; + } + IPADBG("Passed Table handle: 0x%x\n", tbl_hdl); + + if (ipa_nati_add_ipv4_rule(tbl_hdl, clnt_rule, rule_hdl) != 0) { + return result; + } + + IPADBG("returning rule handle 0x%x\n", *rule_hdl); + return 0; +} + + +/** + * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule + * @table_handle: [in] handle of ipv4 nat table + * @rule_handle: [in] ipv4 nat rule handle + * + * To insert new ipv4 nat rule into ipv4 nat table + * + * Returns: 0 On Success, negative on failure + */ +int ipa_nat_del_ipv4_rule(uint32_t tbl_hdl, + uint32_t rule_hdl) +{ + int result = -EINVAL; + + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || + IPA_NAT_INVALID_NAT_ENTRY == rule_hdl) { + IPAERR("invalide parameters\n"); + return result; + } + IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl); + + result = ipa_nati_del_ipv4_rule(tbl_hdl, rule_hdl); + if (result) { + IPAERR("unable to delete rule from hw \n"); + return result; + } + + return 0; +} + +/** + * ipa_nat_query_timestamp() - to query timestamp + * @table_handle: [in] handle of ipv4 nat table + * @rule_handle: [in] ipv4 nat rule handle + * @time_stamp: [out] time stamp of rule + * + * To retrieve the timestamp that lastly the + * nat rule was accessed + * + * Returns: 0 On Success, negative on failure + */ +int ipa_nat_query_timestamp(uint32_t tbl_hdl, + uint32_t rule_hdl, + uint32_t *time_stamp) +{ + + if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS || + NULL == time_stamp) { + IPAERR("invalid parameters passed \n"); + return -EINVAL; + } + IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl); + + return ipa_nati_query_timestamp(tbl_hdl, rule_hdl, time_stamp); +} + + +/** +* ipa_nat_modify_pdn() - modify single PDN entry in the PDN config table +* @table_handle: [in] handle of ipv4 nat table +* @pdn_index : [in] the index of the entry to be modified +* @pdn_info : [in] values for the PDN entry to be changed +* +* Modify a PDN entry +* +* Returns: 0 On Success, negative on failure +*/ +int ipa_nat_modify_pdn(uint32_t tbl_hdl, + uint8_t pdn_index, + ipa_nat_pdn_entry *pdn_info) +{ + struct ipa_ioc_nat_pdn_entry pdn_data; + + if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS) { + IPAERR("invalid parameters passed \n"); + return -EINVAL; + } + + if (!pdn_info) { + IPAERR("pdn_info is NULL \n"); + return -EINVAL; + } + + if (pdn_index > IPA_MAX_PDN_NUM) { + IPAERR("PDN index is out of range %d", pdn_index); + return -EINVAL; + } + + pdn_data.pdn_index = pdn_index; + pdn_data.public_ip = pdn_info->public_ip; + pdn_data.src_metadata = pdn_info->src_metadata; + pdn_data.dst_metadata = pdn_info->dst_metadata; + + return ipa_nati_modify_pdn(&pdn_data); +} + + diff --git a/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drvi.c b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drvi.c new file mode 100644 index 0000000..3e619fe --- /dev/null +++ b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_drvi.c @@ -0,0 +1,2452 @@ +/* +Copyright (c) 2013 - 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 "ipa_nat_drv.h" +#include "ipa_nat_drvi.h" + +#ifdef USE_GLIB +#include <glib.h> +#define strlcpy g_strlcpy +#else +#ifndef FEATURE_IPA_ANDROID +static size_t strlcpy(char * dst, const char * src, size_t size) { + if (size < 1) + return 0; + strncpy(dst, src, size - 1); + dst[size - 1] = 0; + return strlen(dst); +} +#endif +#endif + + +struct ipa_nat_cache ipv4_nat_cache; +pthread_mutex_t nat_mutex = PTHREAD_MUTEX_INITIALIZER; + +static ipa_nat_pdn_entry pdns[IPA_MAX_PDN_NUM]; + +/* ------------------------------------------ + UTILITY FUNCTIONS START + --------------------------------------------*/ + +/** + * UpdateSwSpecParams() - updates sw specific params + * @rule: [in/out] nat table rule + * @param_type: [in] which param need to update + * @value: [in] value of param + * + * Update SW specific params in the passed rule. + * + * Returns: None + */ +void UpdateSwSpecParams(struct ipa_nat_rule *rule, + uint8_t param_type, + uint32_t value) +{ + uint32_t temp = rule->sw_spec_params; + + if (IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE == param_type) { + value = (value << INDX_TBL_ENTRY_SIZE_IN_BITS); + temp &= 0x0000FFFF; + } else { + temp &= 0xFFFF0000; + } + + temp = (temp | value); + rule->sw_spec_params = temp; + return; +} + +/** + * Read8BitFieldValue() + * @rule: [in/out] + * @param_type: [in] + * @value: [in] + * + * + * + * Returns: None + */ + +uint8_t Read8BitFieldValue(uint32_t param, + ipa_nat_rule_field_type fld_type) +{ + void *temp = (void *)¶m; + + switch (fld_type) { + + case PROTOCOL_FIELD: + return ((time_stamp_proto *)temp)->protocol; + + default: + IPAERR("Invalid Field type passed\n"); + return 0; + } +} + +uint16_t Read16BitFieldValue(uint32_t param, + ipa_nat_rule_field_type fld_type) +{ + void *temp = (void *)¶m; + + switch (fld_type) { + + case NEXT_INDEX_FIELD: + return ((next_index_pub_port *)temp)->next_index; + + case PUBLIC_PORT_FILED: + return ((next_index_pub_port *)temp)->public_port; + + case ENABLE_FIELD: + return ((ipcksum_enbl *)temp)->enable; + + case SW_SPEC_PARAM_PREV_INDEX_FIELD: + return ((sw_spec_params *)temp)->prev_index; + + case SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD: + return ((sw_spec_params *)temp)->index_table_entry; + + case INDX_TBL_TBL_ENTRY_FIELD: + return ((tbl_ent_nxt_indx *)temp)->tbl_entry; + + case INDX_TBL_NEXT_INDEX_FILED: + return ((tbl_ent_nxt_indx *)temp)->next_index; + +#ifdef NAT_DUMP + case IP_CHKSUM_FIELD: + return ((ipcksum_enbl *)temp)->ip_chksum; +#endif + + default: + IPAERR("Invalid Field type passed\n"); + return 0; + } +} + +uint32_t Read32BitFieldValue(uint32_t param, + ipa_nat_rule_field_type fld_type) +{ + + void *temp = (void *)¶m; + + switch (fld_type) { + + case TIME_STAMP_FIELD: + return ((time_stamp_proto *)temp)->time_stamp; + + default: + IPAERR("Invalid Field type passed\n"); + return 0; + } +} + +/** +* GetIPAVer(void) - store IPA HW ver in cache +* +* +* Returns: 0 on success, negative on failure +*/ +int GetIPAVer(void) +{ + int ret; + + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_HW_VERSION, &ipv4_nat_cache.ver); + if (ret != 0) { + perror("GetIPAVer(): ioctl error value"); + IPAERR("unable to get IPA version. Error ;%d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EINVAL; + } + IPADBG("IPA version is %d\n", ipv4_nat_cache.ver); + return 0; +} + +/** + * CreateNatDevice() - Create nat devices + * @mem: [in] name of device that need to create + * + * Create Nat device and Register for file create + * notification in given directory and wait till + * receive notification + * + * Returns: 0 on success, negative on failure + */ +int CreateNatDevice(struct ipa_ioc_nat_alloc_mem *mem) +{ + int ret; + + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_ALLOC_NAT_MEM, mem); + if (ret != 0) { + perror("CreateNatDevice(): ioctl error value"); + IPAERR("unable to post nat mem init. Error ;%d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EINVAL; + } + IPADBG("posted IPA_IOC_ALLOC_NAT_MEM to kernel successfully\n"); + return 0; +} + +/** + * GetNearest2Power() - Returns the nearest power of 2 + * @num: [in] given number + * @ret: [out] nearest power of 2 + * + * Returns the nearest power of 2 for a + * given number + * + * Returns: 0 on success, negative on failure + */ +int GetNearest2Power(uint16_t num, uint16_t *ret) +{ + uint16_t number = num; + uint16_t tmp = 1; + *ret = 0; + + if (0 == num) { + return -EINVAL; + } + + if (1 == num) { + *ret = 2; + return 0; + } + + for (;;) { + if (1 == num) { + if (number != tmp) { + tmp *= 2; + } + + *ret = tmp; + return 0; + } + + num >>= 1; + tmp *= 2; + } + + return -EINVAL; +} + +/** + * GetNearestEven() - Returns the nearest even number + * @num: [in] given number + * @ret: [out] nearest even number + * + * Returns the nearest even number for a given number + * + * Returns: 0 on success, negative on failure + */ +void GetNearestEven(uint16_t num, uint16_t *ret) +{ + + if (num < 2) { + *ret = 2; + return; + } + + while ((num % 2) != 0) { + num = num + 1; + } + + *ret = num; + return; +} + +/** + * dst_hash() - Find the index into ipv4 base table + * @public_ip: [in] public_ip + * @trgt_ip: [in] Target IP address + * @trgt_port: [in] Target port + * @public_port: [in] Public port + * @proto: [in] Protocol (TCP/IP) + * @size: [in] size of the ipv4 base Table + * + * This hash method is used to find the hash index of new nat + * entry into ipv4 base table. In case of zero index, the + * new entry will be stored into N-1 index where N is size of + * ipv4 base table + * + * Returns: >0 index into ipv4 base table, negative on failure + */ +static uint16_t dst_hash(uint32_t public_ip, uint32_t trgt_ip, + uint16_t trgt_port, uint16_t public_port, + uint8_t proto, uint16_t size) +{ + uint16_t hash = ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip >> 16)) ^ + (trgt_port) ^ (public_port) ^ (proto); + + if (ipv4_nat_cache.ver >= IPA_HW_v4_0) + hash ^= ((uint16_t)(public_ip)) ^ + ((uint16_t)(public_ip >> 16)); + + IPADBG("public ip 0x%X\n", public_ip); + IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port); + IPADBG("public_port: 0x%x\n", public_port); + IPADBG("proto: 0x%x size: 0x%x\n", proto, size); + + hash = (hash & size); + + /* If the hash resulted to zero then set it to maximum value + as zero is unused entry in nat tables */ + if (0 == hash) { + return size; + } + + IPADBG("dst_hash returning value: %d\n", hash); + return hash; +} + +/** + * src_hash() - Find the index into ipv4 index base table + * @priv_ip: [in] Private IP address + * @priv_port: [in] Private port + * @trgt_ip: [in] Target IP address + * @trgt_port: [in] Target Port + * @proto: [in] Protocol (TCP/IP) + * @size: [in] size of the ipv4 index base Table + * + * This hash method is used to find the hash index of new nat + * entry into ipv4 index base table. In case of zero index, the + * new entry will be stored into N-1 index where N is size of + * ipv4 index base table + * + * Returns: >0 index into ipv4 index base table, negative on failure + */ +static uint16_t src_hash(uint32_t priv_ip, uint16_t priv_port, + uint32_t trgt_ip, uint16_t trgt_port, + uint8_t proto, uint16_t size) +{ + uint16_t hash = ((uint16_t)(priv_ip)) ^ ((uint16_t)(priv_ip >> 16)) ^ + (priv_port) ^ + ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip >> 16)) ^ + (trgt_port) ^ (proto); + + IPADBG("priv_ip: 0x%x priv_port: 0x%x\n", priv_ip, priv_port); + IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port); + IPADBG("proto: 0x%x size: 0x%x\n", proto, size); + + hash = (hash & size); + + /* If the hash resulted to zero then set it to maximum value + as zero is unused entry in nat tables */ + if (0 == hash) { + return size; + } + + IPADBG("src_hash returning value: %d\n", hash); + return hash; +} + +/** + * ipa_nati_calc_ip_cksum() - Calculate the source nat + * IP checksum diff + * @pub_ip_addr: [in] public ip address + * @priv_ip_addr: [in] Private ip address + * + * source nat ip checksum different is calculated as + * public_ip_addr - private_ip_addr + * Here we are using 1's complement to represent -ve number. + * So take 1's complement of private ip addr and add it + * to public ip addr. + * + * Returns: >0 ip checksum diff + */ +static uint16_t ipa_nati_calc_ip_cksum(uint32_t pub_ip_addr, + uint32_t priv_ip_addr) +{ + uint16_t ret; + uint32_t cksum = 0; + + /* Add LSB(2 bytes) of public ip address to cksum */ + cksum += (pub_ip_addr & 0xFFFF); + + /* Add MSB(2 bytes) of public ip address to cksum + and check for carry forward(CF), if any add it + */ + cksum += (pub_ip_addr>>16); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Calculate the 1's complement of private ip address */ + priv_ip_addr = (~priv_ip_addr); + + /* Add LSB(2 bytes) of private ip address to cksum + and check for carry forward(CF), if any add it + */ + cksum += (priv_ip_addr & 0xFFFF); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Add MSB(2 bytes) of private ip address to cksum + and check for carry forward(CF), if any add it + */ + cksum += (priv_ip_addr>>16); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Return the LSB(2 bytes) of checksum */ + ret = (uint16_t)cksum; + return ret; +} + +/** + * ipa_nati_calc_tcp_udp_cksum() - Calculate the source nat + * TCP/UDP checksum diff + * @pub_ip_addr: [in] public ip address + * @pub_port: [in] public tcp/udp port + * @priv_ip_addr: [in] Private ip address + * @priv_port: [in] Private tcp/udp prot + * + * source nat tcp/udp checksum is calculated as + * (pub_ip_addr + pub_port) - (priv_ip_addr + priv_port) + * Here we are using 1's complement to represent -ve number. + * So take 1's complement of prviate ip addr &private port + * and add it public ip addr & public port. + * + * Returns: >0 tcp/udp checksum diff + */ +static uint16_t ipa_nati_calc_tcp_udp_cksum(uint32_t pub_ip_addr, + uint16_t pub_port, + uint32_t priv_ip_addr, + uint16_t priv_port) +{ + uint16_t ret = 0; + uint32_t cksum = 0; + + /* Add LSB(2 bytes) of public ip address to cksum */ + cksum += (pub_ip_addr & 0xFFFF); + + /* Add MSB(2 bytes) of public ip address to cksum + and check for carry forward(CF), if any add it + */ + cksum += (pub_ip_addr>>16); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Add public port to cksum and + check for carry forward(CF), if any add it */ + cksum += pub_port; + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Calculate the 1's complement of private ip address */ + priv_ip_addr = (~priv_ip_addr); + + /* Add LSB(2 bytes) of private ip address to cksum + and check for carry forward(CF), if any add it + */ + cksum += (priv_ip_addr & 0xFFFF); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Add MSB(2 bytes) of private ip address to cksum + and check for carry forward(CF), if any add + */ + cksum += (priv_ip_addr>>16); + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* Calculate the 1's complement of private port */ + priv_port = (~priv_port); + + /* Add public port to cksum and + check for carry forward(CF), if any add it */ + cksum += priv_port; + if (cksum >> 16) { + cksum = (cksum & 0x0000FFFF); + cksum += 1; + } + + /* return the LSB(2 bytes) of checksum */ + ret = (uint16_t)cksum; + return ret; +} + +/** + * ipa_nati_make_rule_hdl() - makes nat rule handle + * @tbl_hdl: [in] nat table handle + * @tbl_entry: [in] nat table entry + * + * Calculate the nat rule handle which from + * nat entry which will be returned to client of + * nat driver + * + * Returns: >0 nat rule handle + */ +uint16_t ipa_nati_make_rule_hdl(uint16_t tbl_hdl, + uint16_t tbl_entry) +{ + struct ipa_nat_ip4_table_cache *tbl_ptr; + uint16_t rule_hdl = 0; + uint16_t cnt = 0; + + tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1]; + + if (tbl_entry >= tbl_ptr->table_entries) { + /* Increase the current expansion table count */ + tbl_ptr->cur_expn_tbl_cnt++; + + /* Update the index into table */ + rule_hdl = tbl_entry - tbl_ptr->table_entries; + rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS); + /* Update the table type mask */ + rule_hdl = (rule_hdl | IPA_NAT_RULE_HDL_TBL_TYPE_MASK); + } else { + /* Increase the current count */ + tbl_ptr->cur_tbl_cnt++; + + rule_hdl = tbl_entry; + rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS); + } + + for (; cnt < (tbl_ptr->table_entries + tbl_ptr->expn_table_entries); cnt++) { + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_ptr->rule_id_array[cnt]) { + tbl_ptr->rule_id_array[cnt] = rule_hdl; + return cnt + 1; + } + } + + return 0; +} + +/** + * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle + * @tbl_hdl: [in] nat table rule + * @rule_hdl: [in] nat rule handle + * @expn_tbl: [out] expansion table or not + * @tbl_entry: [out] index into table + * + * Parse the rule handle to retrieve the nat table + * type and entry of nat table + * + * Returns: None + */ +void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_index, + uint16_t rule_hdl, uint8_t *expn_tbl, + uint16_t *tbl_entry) +{ + struct ipa_nat_ip4_table_cache *tbl_ptr; + uint16_t rule_id; + + *expn_tbl = 0; + *tbl_entry = IPA_NAT_INVALID_NAT_ENTRY; + tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_index]; + + if (rule_hdl >= (tbl_ptr->table_entries + tbl_ptr->expn_table_entries)) { + IPAERR("invalid rule handle\n"); + return; + } + + rule_id = tbl_ptr->rule_id_array[rule_hdl-1]; + + /* Retrieve the table type */ + *expn_tbl = 0; + if (rule_id & IPA_NAT_RULE_HDL_TBL_TYPE_MASK) { + *expn_tbl = 1; + } + + /* Retrieve the table entry */ + *tbl_entry = (rule_id >> IPA_NAT_RULE_HDL_TBL_TYPE_BITS); + return; +} + +uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr, + nat_table_type tbl_type, + uint16_t tbl_entry) +{ + struct ipa_nat_rule *tbl_ptr; + uint32_t ret = 0; + + if (IPA_NAT_EXPN_TBL == tbl_type) { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr; + } else { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr; + } + + ret = (char *)&tbl_ptr[tbl_entry] - (char *)tbl_ptr; + ret += cache_ptr->tbl_addr_offset; + return ret; +} + +uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr, + nat_table_type tbl_type, + uint16_t indx_tbl_entry) +{ + struct ipa_nat_indx_tbl_rule *indx_tbl_ptr; + uint32_t ret = 0; + + if (IPA_NAT_INDEX_EXPN_TBL == tbl_type) { + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr; + } else { + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr; + } + + ret = (char *)&indx_tbl_ptr[indx_tbl_entry] - (char *)indx_tbl_ptr; + ret += cache_ptr->tbl_addr_offset; + return ret; +} + +/* ------------------------------------------ + UTILITY FUNCTIONS END +--------------------------------------------*/ + +/* ------------------------------------------ + Main Functions +--------------------------------------------**/ +void ipa_nati_reset_tbl(uint8_t tbl_indx) +{ + uint16_t table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries; + uint16_t expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].expn_table_entries; + + /* Base table */ + IPADBG("memset() base table to 0, %p\n", + ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr); + + memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr, + 0, + IPA_NAT_TABLE_ENTRY_SIZE * table_entries); + + /* Base expansino table */ + IPADBG("memset() expn base table to 0, %p\n", + ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr); + + memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr, + 0, + IPA_NAT_TABLE_ENTRY_SIZE * expn_table_entries); + + /* Index table */ + IPADBG("memset() index table to 0, %p\n", + ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr); + + memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr, + 0, + IPA_NAT_INDEX_TABLE_ENTRY_SIZE * table_entries); + + /* Index expansion table */ + IPADBG("memset() index expn table to 0, %p\n", + ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr); + + memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr, + 0, + IPA_NAT_INDEX_TABLE_ENTRY_SIZE * expn_table_entries); + + IPADBG("returning from ipa_nati_reset_tbl()\n"); + return; +} + +int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr, + uint16_t number_of_entries, + uint32_t *tbl_hdl) +{ + struct ipa_ioc_nat_alloc_mem mem; + uint8_t tbl_indx = ipv4_nat_cache.table_cnt; + uint16_t table_entries, expn_table_entries; + int ret; + + *tbl_hdl = 0; + /* Allocate table */ + memset(&mem, 0, sizeof(mem)); + ret = ipa_nati_alloc_table(number_of_entries, + &mem, + &table_entries, + &expn_table_entries); + if (0 != ret) { + IPAERR("unable to allocate nat table\n"); + return -ENOMEM; + } + + /* Update the cache + The (IPA_NAT_UNUSED_BASE_ENTRIES/2) indicates zero entry entries + for both base and expansion table + */ + ret = ipa_nati_update_cache(&mem, + public_ip_addr, + table_entries, + expn_table_entries); + if (0 != ret) { + IPAERR("unable to update cache Error: %d\n", ret); + return -EINVAL; + } + + /* Reset the nat table before posting init cmd */ + ipa_nati_reset_tbl(tbl_indx); + + /* Initialize the ipa hw with nat table dimensions */ + ret = ipa_nati_post_ipv4_init_cmd(tbl_indx); + if (0 != ret) { + IPAERR("unable to post nat_init command Error %d\n", ret); + return -EINVAL; + } + + /* store the initial public ip address in the cached pdn table + this is backward compatible for pre IPAv4 versions, we will always + use this ip as the single PDN address + */ + pdns[0].public_ip = public_ip_addr; + + /* Return table handle */ + ipv4_nat_cache.table_cnt++; + *tbl_hdl = ipv4_nat_cache.table_cnt; + +#ifdef NAT_DUMP + ipa_nat_dump_ipv4_table(*tbl_hdl); +#endif + return 0; +} + +int ipa_nati_alloc_table(uint16_t number_of_entries, + struct ipa_ioc_nat_alloc_mem *mem, + uint16_t *table_entries, + uint16_t *expn_table_entries) +{ + int fd = 0, ret; + uint16_t total_entries; + + /* Copy the table name */ + strlcpy(mem->dev_name, NAT_DEV_NAME, IPA_RESOURCE_NAME_MAX); + + /* Calculate the size for base table and expansion table */ + *table_entries = (uint16_t)(number_of_entries * IPA_NAT_BASE_TABLE_PERCENTAGE); + if (*table_entries == 0) { + *table_entries = 1; + } + if (GetNearest2Power(*table_entries, table_entries)) { + IPAERR("unable to calculate power of 2\n"); + return -EINVAL; + } + + *expn_table_entries = (uint16_t)(number_of_entries * IPA_NAT_EXPANSION_TABLE_PERCENTAGE); + GetNearestEven(*expn_table_entries, expn_table_entries); + + total_entries = (*table_entries)+(*expn_table_entries); + + /* Calclate the memory size for both table and index table entries */ + mem->size = (IPA_NAT_TABLE_ENTRY_SIZE * total_entries); + IPADBG("Nat Table size: %zu\n", mem->size); + mem->size += (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * total_entries); + IPADBG("Nat Base and Index Table size: %zu\n", mem->size); + + if (!ipv4_nat_cache.ipa_fd) { + fd = open(IPA_DEV_NAME, O_RDONLY); + if (fd < 0) { + perror("ipa_nati_alloc_table(): open error value:"); + IPAERR("unable to open ipa device\n"); + return -EIO; + } + ipv4_nat_cache.ipa_fd = fd; + } + + if (GetIPAVer()) { + IPAERR("unable to get ipa ver\n"); + return -EIO; + } + + ret = CreateNatDevice(mem); + return ret; +} + + +int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *mem, + uint32_t public_addr, + uint16_t tbl_entries, + uint16_t expn_tbl_entries) +{ + uint32_t index = ipv4_nat_cache.table_cnt; + char *ipv4_rules_addr = NULL; + + int fd = 0; + int flags = MAP_SHARED; + int prot = PROT_READ | PROT_WRITE; + off_t offset = 0; +#ifdef IPA_ON_R3PC + int ret = 0; + uint32_t nat_mem_offset = 0; +#endif + + ipv4_nat_cache.ip4_tbl[index].valid = IPA_NAT_TABLE_VALID; + ipv4_nat_cache.ip4_tbl[index].public_addr = public_addr; + ipv4_nat_cache.ip4_tbl[index].size = mem->size; + ipv4_nat_cache.ip4_tbl[index].tbl_addr_offset = mem->offset; + + ipv4_nat_cache.ip4_tbl[index].table_entries = tbl_entries; + ipv4_nat_cache.ip4_tbl[index].expn_table_entries = expn_tbl_entries; + + IPADBG("num of ipv4 rules:%d\n", tbl_entries); + IPADBG("num of ipv4 expn rules:%d\n", expn_tbl_entries); + + /* allocate memory for nat index expansion table */ + if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta) { + ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta = + malloc(sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries); + + if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta) { + IPAERR("Fail to allocate ipv4 index expansion table meta\n"); + return 0; + } + + memset(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta, + 0, + sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries); + } + + /* Allocate memory for rule_id_array */ + if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array) { + ipv4_nat_cache.ip4_tbl[index].rule_id_array = + malloc(sizeof(uint16_t) * (tbl_entries + expn_tbl_entries)); + + if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array) { + IPAERR("Fail to allocate rule id array\n"); + return 0; + } + + memset(ipv4_nat_cache.ip4_tbl[index].rule_id_array, + 0, + sizeof(uint16_t) * (tbl_entries + expn_tbl_entries)); + } + + + /* open the nat table */ + strlcpy(mem->dev_name, NAT_DEV_FULL_NAME, IPA_RESOURCE_NAME_MAX); + fd = open(mem->dev_name, O_RDWR); + if (fd < 0) { + perror("ipa_nati_update_cache(): open error value:"); + IPAERR("unable to open nat device. Error:%d\n", fd); + return -EIO; + } + + /* copy the nat table name */ + strlcpy(ipv4_nat_cache.ip4_tbl[index].table_name, + mem->dev_name, + IPA_RESOURCE_NAME_MAX); + ipv4_nat_cache.ip4_tbl[index].nat_fd = fd; + + /* open the nat device Table */ +#ifndef IPA_ON_R3PC + ipv4_rules_addr = (void *)mmap(NULL, mem->size, + prot, flags, + fd, offset); +#else + IPADBG("user space r3pc\n"); + ipv4_rules_addr = (void *)mmap((caddr_t)0, NAT_MMAP_MEM_SIZE, + prot, flags, + fd, offset); +#endif + if (MAP_FAILED == ipv4_rules_addr) { + perror("unable to mmap the memory\n"); + return -EINVAL; + } + +#ifdef IPA_ON_R3PC + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_NAT_OFFSET, &nat_mem_offset); + if (ret != 0) { + perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value"); + IPAERR("unable to post ant offset cmd Error: %d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EIO; + } + ipv4_rules_addr += nat_mem_offset; + ipv4_nat_cache.ip4_tbl[index].mmap_offset = nat_mem_offset; +#endif + + IPADBG("mmap return value 0x%lx\n", (long unsigned int)ipv4_rules_addr); + + ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr = ipv4_rules_addr; + + ipv4_nat_cache.ip4_tbl[index].ipv4_expn_rules_addr = + ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * tbl_entries); + + ipv4_nat_cache.ip4_tbl[index].index_table_addr = + ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries)); + + ipv4_nat_cache.ip4_tbl[index].index_table_expn_addr = + ipv4_rules_addr + + (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries))+ + (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * tbl_entries); + + return 0; +} + +/* comment: check the implementation once + offset should be in terms of byes */ +int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index) +{ + struct ipa_ioc_v4_nat_init cmd; + uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_index].tbl_addr_offset; + int ret; + + cmd.tbl_index = tbl_index; + + cmd.ipv4_rules_offset = offset; + cmd.expn_rules_offset = cmd.ipv4_rules_offset + + (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_TABLE_ENTRY_SIZE); + + cmd.index_offset = cmd.expn_rules_offset + + (ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries * IPA_NAT_TABLE_ENTRY_SIZE); + + cmd.index_expn_offset = cmd.index_offset + + (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_INDEX_TABLE_ENTRY_SIZE); + + cmd.table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].table_entries - 1; + cmd.expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries; + + cmd.ip_addr = ipv4_nat_cache.ip4_tbl[tbl_index].public_addr; + + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_INIT_NAT, &cmd); + if (ret != 0) { + perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value"); + IPAERR("unable to post init cmd Error: %d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EINVAL; + } + IPADBG("Posted IPA_IOC_V4_INIT_NAT to kernel successfully\n"); + + return 0; +} + +int ipa_nati_del_ipv4_table(uint32_t tbl_hdl) +{ + uint8_t index = (uint8_t)(tbl_hdl - 1); + void *addr = (void *)ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr; + struct ipa_ioc_v4_nat_del del_cmd; + int ret; + + if (!ipv4_nat_cache.ip4_tbl[index].valid) { + IPAERR("invalid table handle passed\n"); + ret = -EINVAL; + goto fail; + } + + if (pthread_mutex_lock(&nat_mutex) != 0) { + ret = -1; + goto lock_mutex_fail; + } + + /* unmap the device memory from user space */ +#ifndef IPA_ON_R3PC + munmap(addr, ipv4_nat_cache.ip4_tbl[index].size); +#else + addr = (char *)addr - ipv4_nat_cache.ip4_tbl[index].mmap_offset; + munmap(addr, NAT_MMAP_MEM_SIZE); +#endif + + /* close the file descriptor of nat device */ + if (close(ipv4_nat_cache.ip4_tbl[index].nat_fd)) { + IPAERR("unable to close the file descriptor\n"); + ret = -EINVAL; + if (pthread_mutex_unlock(&nat_mutex) != 0) + goto unlock_mutex_fail; + goto fail; + } + + del_cmd.table_index = index; + del_cmd.public_ip_addr = ipv4_nat_cache.ip4_tbl[index].public_addr; + ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_DEL_NAT, &del_cmd); + if (ret != 0) { + perror("ipa_nati_del_ipv4_table(): ioctl error value"); + IPAERR("unable to post nat del command init Error: %d\n", ret); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + ret = -EINVAL; + if (pthread_mutex_unlock(&nat_mutex) != 0) + goto unlock_mutex_fail; + goto fail; + } + IPAERR("posted IPA_IOC_V4_DEL_NAT to kernel successfully\n"); + + free(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta); + free(ipv4_nat_cache.ip4_tbl[index].rule_id_array); + + memset(&ipv4_nat_cache.ip4_tbl[index], + 0, + sizeof(ipv4_nat_cache.ip4_tbl[index])); + + /* Decrease the table count by 1*/ + ipv4_nat_cache.table_cnt--; + + if (pthread_mutex_unlock(&nat_mutex) != 0) { + ret = -1; + goto unlock_mutex_fail; + } + + return 0; + +lock_mutex_fail: + IPAERR("unable to lock the nat mutex\n"); + return ret; + +unlock_mutex_fail: + IPAERR("unable to unlock the nat mutex\n"); + +fail: + return ret; +} + +int ipa_nati_query_timestamp(uint32_t tbl_hdl, + uint32_t rule_hdl, + uint32_t *time_stamp) +{ + uint8_t tbl_index = (uint8_t)(tbl_hdl - 1); + uint8_t expn_tbl = 0; + uint16_t tbl_entry = 0; + struct ipa_nat_rule *tbl_ptr = NULL; + + if (!ipv4_nat_cache.ip4_tbl[tbl_index].valid) { + IPAERR("invalid table handle\n"); + return -EINVAL; + } + + if (pthread_mutex_lock(&nat_mutex) != 0) { + IPAERR("unable to lock the nat mutex\n"); + return -1; + } + + ipa_nati_parse_ipv4_rule_hdl(tbl_index, (uint16_t)rule_hdl, + &expn_tbl, &tbl_entry); + + tbl_ptr = + (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_rules_addr; + if (expn_tbl) { + tbl_ptr = + (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_expn_rules_addr; + } + + if (tbl_ptr) + *time_stamp = Read32BitFieldValue(tbl_ptr[tbl_entry].ts_proto, + TIME_STAMP_FIELD); + + if (pthread_mutex_unlock(&nat_mutex) != 0) { + IPAERR("unable to unlock the nat mutex\n"); + return -1; + } + + return 0; +} + +int ipa_nati_modify_pdn(struct ipa_ioc_nat_pdn_entry *entry) +{ + if (entry->public_ip == 0) + IPADBG("PDN %d public ip will be set to 0\n", entry->pdn_index); + + if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_MODIFY_PDN, entry)) { + perror("ipa_nati_modify_pdn(): ioctl error value"); + IPAERR("unable to call modify pdn icotl\n"); + IPAERR("index %d, ip 0x%X, src_metdata 0x%X, dst_metadata 0x%X\n", + entry->pdn_index, entry->public_ip, entry->src_metadata, entry->dst_metadata); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + return -EIO; + } + + pdns[entry->pdn_index].public_ip = entry->public_ip; + pdns[entry->pdn_index].dst_metadata = entry->dst_metadata; + pdns[entry->pdn_index].src_metadata = entry->src_metadata; + + IPADBG("posted IPA_IOC_NAT_MODIFY_PDN to kernel successfully and stored in cache\n index %d, ip 0x%X, src_metdata 0x%X, dst_metadata 0x%X\n", + entry->pdn_index, entry->public_ip, entry->src_metadata, entry->dst_metadata); + + return 0; +} + +int ipa_nati_add_ipv4_rule(uint32_t tbl_hdl, + const ipa_nat_ipv4_rule *clnt_rule, + uint32_t *rule_hdl) +{ + struct ipa_nat_ip4_table_cache *tbl_ptr; + struct ipa_nat_sw_rule sw_rule; + struct ipa_nat_indx_tbl_sw_rule index_sw_rule; + uint16_t new_entry, new_index_tbl_entry; + + /* verify that the rule's PDN is valid */ + if (clnt_rule->pdn_index >= IPA_MAX_PDN_NUM || + pdns[clnt_rule->pdn_index].public_ip == 0) { + IPAERR("invalid parameters, pdn index %d, public ip = 0x%X\n", + clnt_rule->pdn_index, pdns[clnt_rule->pdn_index].public_ip); + return -EINVAL; + } + + memset(&sw_rule, 0, sizeof(sw_rule)); + memset(&index_sw_rule, 0, sizeof(index_sw_rule)); + + /* Generate rule from client input */ + if (ipa_nati_generate_rule(tbl_hdl, clnt_rule, + &sw_rule, &index_sw_rule, + &new_entry, &new_index_tbl_entry)) { + IPAERR("unable to generate rule\n"); + return -EINVAL; + } + + tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1]; + ipa_nati_copy_ipv4_rule_to_hw(tbl_ptr, &sw_rule, new_entry, (uint8_t)(tbl_hdl-1)); + ipa_nati_copy_ipv4_index_rule_to_hw(tbl_ptr, + &index_sw_rule, + new_index_tbl_entry, + (uint8_t)(tbl_hdl-1)); + + IPADBG("new entry:%d, new index entry: %d\n", new_entry, new_index_tbl_entry); + if (ipa_nati_post_ipv4_dma_cmd((uint8_t)(tbl_hdl - 1), new_entry)) { + IPAERR("unable to post dma command\n"); + return -EIO; + } + + /* Generate rule handle */ + *rule_hdl = ipa_nati_make_rule_hdl((uint16_t)tbl_hdl, new_entry); + if (!(*rule_hdl)) { + IPAERR("unable to generate rule handle\n"); + return -EINVAL; + } + +#ifdef NAT_DUMP + ipa_nat_dump_ipv4_table(tbl_hdl); +#endif + + return 0; +} + +int ipa_nati_generate_rule(uint32_t tbl_hdl, + const ipa_nat_ipv4_rule *clnt_rule, + struct ipa_nat_sw_rule *rule, + struct ipa_nat_indx_tbl_sw_rule *index_sw_rule, + uint16_t *tbl_entry, + uint16_t *indx_tbl_entry) +{ + struct ipa_nat_ip4_table_cache *tbl_ptr; + uint16_t tmp; + + if (NULL == clnt_rule || NULL == index_sw_rule || + NULL == rule || NULL == tbl_entry || + NULL == indx_tbl_entry) { + IPAERR("invalid parameters\n"); + return -EINVAL; + } + + tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1]; + + *tbl_entry = ipa_nati_generate_tbl_rule(clnt_rule, + rule, + tbl_ptr); + if (IPA_NAT_INVALID_NAT_ENTRY == *tbl_entry) { + IPAERR("unable to generate table entry\n"); + return -EINVAL; + } + + index_sw_rule->tbl_entry = *tbl_entry; + *indx_tbl_entry = ipa_nati_generate_index_rule(clnt_rule, + index_sw_rule, + tbl_ptr); + if (IPA_NAT_INVALID_NAT_ENTRY == *indx_tbl_entry) { + IPAERR("unable to generate index table entry\n"); + return -EINVAL; + } + + rule->indx_tbl_entry = *indx_tbl_entry; + if (*indx_tbl_entry >= tbl_ptr->table_entries) { + tmp = *indx_tbl_entry - tbl_ptr->table_entries; + tbl_ptr->index_expn_table_meta[tmp].prev_index = index_sw_rule->prev_index; + } + + return 0; +} + +uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule, + struct ipa_nat_sw_rule *sw_rule, + struct ipa_nat_ip4_table_cache *tbl_ptr) +{ + uint32_t pub_ip_addr; + uint16_t prev = 0, nxt_indx = 0, new_entry; + struct ipa_nat_rule *tbl = NULL, *expn_tbl = NULL; + + pub_ip_addr = pdns[clnt_rule->pdn_index].public_ip; + + tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_rules_addr; + expn_tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_expn_rules_addr; + + /* copy the values from client rule to sw rule */ + sw_rule->private_ip = clnt_rule->private_ip; + sw_rule->private_port = clnt_rule->private_port; + sw_rule->protocol = clnt_rule->protocol; + sw_rule->public_port = clnt_rule->public_port; + sw_rule->target_ip = clnt_rule->target_ip; + sw_rule->target_port = clnt_rule->target_port; + sw_rule->pdn_index = clnt_rule->pdn_index; + + /* consider only public and private ip fields */ + sw_rule->ip_chksum = ipa_nati_calc_ip_cksum(pub_ip_addr, + clnt_rule->private_ip); + + if (IPPROTO_TCP == sw_rule->protocol || + IPPROTO_UDP == sw_rule->protocol) { + /* consider public and private ip & port fields */ + sw_rule->tcp_udp_chksum = ipa_nati_calc_tcp_udp_cksum( + pub_ip_addr, + clnt_rule->public_port, + clnt_rule->private_ip, + clnt_rule->private_port); + } + + sw_rule->rsvd1 = 0; + sw_rule->enable = IPA_NAT_FLAG_DISABLE_BIT; + sw_rule->next_index = 0; + + /* + SW sets this timer to 0. + The assumption is that 0 is an invalid clock value and no clock + wraparounds are expected + */ + sw_rule->time_stamp = 0; + sw_rule->rsvd2 = 0; + sw_rule->rsvd3 = 0; + sw_rule->prev_index = 0; + sw_rule->indx_tbl_entry = 0; + + new_entry = dst_hash(pub_ip_addr, clnt_rule->target_ip, + clnt_rule->target_port, + clnt_rule->public_port, + clnt_rule->protocol, + tbl_ptr->table_entries-1); + + /* check whether there is any collision + if no collision return */ + if (!Read16BitFieldValue(tbl[new_entry].ip_cksm_enbl, + ENABLE_FIELD)) { + sw_rule->prev_index = 0; + IPADBG("Destination Nat New Entry Index %d\n", new_entry); + return new_entry; + } + + /* First collision */ + if (Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) { + sw_rule->prev_index = new_entry; + } else { /* check for more than one collision */ + /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */ + nxt_indx = Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD); + + while (nxt_indx != IPA_NAT_INVALID_NAT_ENTRY) { + prev = nxt_indx; + + nxt_indx -= tbl_ptr->table_entries; + nxt_indx = Read16BitFieldValue(expn_tbl[nxt_indx].nxt_indx_pub_port, + NEXT_INDEX_FIELD); + + /* Handling error case */ + if (prev == nxt_indx) { + IPAERR("Error: Prev index:%d and next:%d index should not be same\n", prev, nxt_indx); + return IPA_NAT_INVALID_NAT_ENTRY; + } + } + + sw_rule->prev_index = prev; + } + + /* On collision check for the free entry in expansion table */ + new_entry = ipa_nati_expn_tbl_free_entry(expn_tbl, + tbl_ptr->expn_table_entries); + + if (IPA_NAT_INVALID_NAT_ENTRY == new_entry) { + /* Expansion table is full return*/ + IPAERR("Expansion table is full\n"); + IPAERR("Current Table: %d & Expn Entries: %d\n", + tbl_ptr->cur_tbl_cnt, tbl_ptr->cur_expn_tbl_cnt); + return IPA_NAT_INVALID_NAT_ENTRY; + } + new_entry += tbl_ptr->table_entries; + + IPADBG("new entry index %d\n", new_entry); + return new_entry; +} + +/* returns expn table entry index */ +uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl, + uint16_t size) +{ + int cnt; + + for (cnt = 1; cnt < size; cnt++) { + if (!Read16BitFieldValue(expn_tbl[cnt].ip_cksm_enbl, + ENABLE_FIELD)) { + IPADBG("new expansion table entry index %d\n", cnt); + return cnt; + } + } + + IPAERR("nat expansion table is full\n"); + return 0; +} + +uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule, + struct ipa_nat_indx_tbl_sw_rule *sw_rule, + struct ipa_nat_ip4_table_cache *tbl_ptr) +{ + struct ipa_nat_indx_tbl_rule *indx_tbl, *indx_expn_tbl; + uint16_t prev = 0, nxt_indx = 0, new_entry; + + indx_tbl = + (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_addr; + indx_expn_tbl = + (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_expn_addr; + + new_entry = src_hash(clnt_rule->private_ip, + clnt_rule->private_port, + clnt_rule->target_ip, + clnt_rule->target_port, + clnt_rule->protocol, + tbl_ptr->table_entries-1); + + /* check whether there is any collision + if no collision return */ + if (!Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + sw_rule->prev_index = 0; + IPADBG("Source Nat Index Table Entry %d\n", new_entry); + return new_entry; + } + + /* check for more than one collision */ + if (Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) { + sw_rule->prev_index = new_entry; + IPADBG("First collosion. Entry %d\n", new_entry); + } else { + /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */ + nxt_indx = Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + while (nxt_indx != IPA_NAT_INVALID_NAT_ENTRY) { + prev = nxt_indx; + + nxt_indx -= tbl_ptr->table_entries; + nxt_indx = Read16BitFieldValue(indx_expn_tbl[nxt_indx].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + /* Handling error case */ + if (prev == nxt_indx) { + IPAERR("Error: Prev:%d and next:%d index should not be same\n", prev, nxt_indx); + return IPA_NAT_INVALID_NAT_ENTRY; + } + } + + sw_rule->prev_index = prev; + } + + /* On collision check for the free entry in expansion table */ + new_entry = ipa_nati_index_expn_get_free_entry(indx_expn_tbl, + tbl_ptr->expn_table_entries); + + if (IPA_NAT_INVALID_NAT_ENTRY == new_entry) { + /* Expansion table is full return*/ + IPAERR("Index expansion table is full\n"); + IPAERR("Current Table: %d & Expn Entries: %d\n", + tbl_ptr->cur_tbl_cnt, tbl_ptr->cur_expn_tbl_cnt); + return IPA_NAT_INVALID_NAT_ENTRY; + } + new_entry += tbl_ptr->table_entries; + + + if (sw_rule->prev_index == new_entry) { + IPAERR("Error: prev_entry:%d ", sw_rule->prev_index); + IPAERR("and new_entry:%d should not be same ", new_entry); + IPAERR("infinite loop detected\n"); + return IPA_NAT_INVALID_NAT_ENTRY; + } + + IPADBG("index table entry %d\n", new_entry); + return new_entry; +} + +/* returns index expn table entry index */ +uint16_t ipa_nati_index_expn_get_free_entry( + struct ipa_nat_indx_tbl_rule *indx_tbl, + uint16_t size) +{ + int cnt; + for (cnt = 1; cnt < size; cnt++) { + if (!Read16BitFieldValue(indx_tbl[cnt].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + return cnt; + } + } + + IPAERR("nat index expansion table is full\n"); + return 0; +} + +void ipa_nati_write_next_index(uint8_t tbl_indx, + nat_table_type tbl_type, + uint16_t value, + uint32_t offset) +{ + struct ipa_ioc_nat_dma_cmd *cmd; + + IPADBG("Updating next index field of table %d on collosion using dma\n", tbl_type); + IPADBG("table index: %d, value: %d offset;%d\n", tbl_indx, value, offset); + + cmd = (struct ipa_ioc_nat_dma_cmd *) + malloc(sizeof(struct ipa_ioc_nat_dma_cmd)+ + sizeof(struct ipa_ioc_nat_dma_one)); + if (NULL == cmd) { + IPAERR("unable to allocate memory\n"); + return; + } + + cmd->dma[0].table_index = tbl_indx; + cmd->dma[0].base_addr = tbl_type; + cmd->dma[0].data = value; + cmd->dma[0].offset = offset; + + cmd->entries = 1; + if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) { + perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value"); + IPAERR("unable to call dma icotl to update next index\n"); + IPAERR("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + goto fail; + } + +fail: + free(cmd); + + return; +} + +void ipa_nati_copy_ipv4_rule_to_hw( + struct ipa_nat_ip4_table_cache *ipv4_cache, + struct ipa_nat_sw_rule *rule, + uint16_t entry, uint8_t tbl_index) +{ + struct ipa_nat_rule *tbl_ptr; + uint16_t prev_entry = rule->prev_index; + nat_table_type tbl_type; + uint32_t offset = 0; + + if (entry < ipv4_cache->table_entries) { + tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr; + + memcpy(&tbl_ptr[entry], + rule, + sizeof(struct ipa_nat_rule)); + } else { + tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_expn_rules_addr; + memcpy(&tbl_ptr[entry - ipv4_cache->table_entries], + rule, + sizeof(struct ipa_nat_rule)); + } + + /* Update the previos entry next_index */ + if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry) { + + if (prev_entry < ipv4_cache->table_entries) { + tbl_type = IPA_NAT_BASE_TBL; + tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr; + } else { + tbl_type = IPA_NAT_EXPN_TBL; + /* tbp_ptr is already pointing to expansion table + no need to initialize it */ + prev_entry = prev_entry - ipv4_cache->table_entries; + } + + offset = ipa_nati_get_entry_offset(ipv4_cache, tbl_type, prev_entry); + offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET; + + ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset); + } + + return; +} + +void ipa_nati_copy_ipv4_index_rule_to_hw( + struct ipa_nat_ip4_table_cache *ipv4_cache, + struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule, + uint16_t entry, + uint8_t tbl_index) +{ + struct ipa_nat_indx_tbl_rule *tbl_ptr; + struct ipa_nat_sw_indx_tbl_rule sw_rule; + uint16_t prev_entry = indx_sw_rule->prev_index; + nat_table_type tbl_type; + uint16_t offset = 0; + + sw_rule.next_index = indx_sw_rule->next_index; + sw_rule.tbl_entry = indx_sw_rule->tbl_entry; + + if (entry < ipv4_cache->table_entries) { + tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr; + + memcpy(&tbl_ptr[entry], + &sw_rule, + sizeof(struct ipa_nat_indx_tbl_rule)); + } else { + tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_expn_addr; + + memcpy(&tbl_ptr[entry - ipv4_cache->table_entries], + &sw_rule, + sizeof(struct ipa_nat_indx_tbl_rule)); + } + + /* Update the next field of previous entry on collosion */ + if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry) { + if (prev_entry < ipv4_cache->table_entries) { + tbl_type = IPA_NAT_INDX_TBL; + tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr; + } else { + tbl_type = IPA_NAT_INDEX_EXPN_TBL; + /* tbp_ptr is already pointing to expansion table + no need to initialize it */ + prev_entry = prev_entry - ipv4_cache->table_entries; + } + + offset = ipa_nati_get_index_entry_offset(ipv4_cache, tbl_type, prev_entry); + offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET; + + IPADBG("Updating next index field of index table on collosion using dma()\n"); + ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset); + } + + return; +} + +int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx, + uint16_t entry) +{ + struct ipa_ioc_nat_dma_cmd *cmd; + struct ipa_nat_rule *tbl_ptr; + uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_indx].tbl_addr_offset; + int ret = 0; + + cmd = (struct ipa_ioc_nat_dma_cmd *) + malloc(sizeof(struct ipa_ioc_nat_dma_cmd)+ + sizeof(struct ipa_ioc_nat_dma_one)); + if (NULL == cmd) { + IPAERR("unable to allocate memory\n"); + return -ENOMEM; + } + + if (entry < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries) { + tbl_ptr = + (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr; + + cmd->dma[0].table_index = tbl_indx; + cmd->dma[0].base_addr = IPA_NAT_BASE_TBL; + cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK; + + cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr; + cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET; + } else { + tbl_ptr = + (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr; + entry = entry - ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries; + + cmd->dma[0].table_index = tbl_indx; + cmd->dma[0].base_addr = IPA_NAT_EXPN_TBL; + cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK; + + cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr; + cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET; + cmd->dma[0].offset += offset; + } + + cmd->entries = 1; + if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) { + perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value"); + IPAERR("unable to call dma icotl\n"); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + ret = -EIO; + goto fail; + } + IPADBG("posted IPA_IOC_NAT_DMA to kernel successfully during add operation\n"); + + +fail: + free(cmd); + + return ret; +} + + +int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl, + uint32_t rule_hdl) +{ + uint8_t expn_tbl; + uint16_t tbl_entry; + struct ipa_nat_ip4_table_cache *tbl_ptr; + del_type rule_pos; + uint8_t tbl_indx = (uint8_t)(tbl_hdl - 1); + int ret; + + /* Parse the rule handle */ + ipa_nati_parse_ipv4_rule_hdl(tbl_indx, (uint16_t)rule_hdl, + &expn_tbl, &tbl_entry); + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_entry) { + IPAERR("Invalid Rule Entry\n"); + ret = -EINVAL; + goto fail; + } + + if (pthread_mutex_lock(&nat_mutex) != 0) { + ret = -1; + goto mutex_lock_error; + } + + IPADBG("Delete below rule\n"); + IPADBG("tbl_entry:%d expn_tbl:%d\n", tbl_entry, expn_tbl); + + tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx]; + if (!tbl_ptr->valid) { + IPAERR("invalid table handle\n"); + ret = -EINVAL; + if (pthread_mutex_unlock(&nat_mutex) != 0) + goto mutex_unlock_error; + goto fail; + } + + ipa_nati_find_rule_pos(tbl_ptr, expn_tbl, + tbl_entry, &rule_pos); + IPADBG("rule_pos:%d\n", rule_pos); + + if (ipa_nati_post_del_dma_cmd(tbl_indx, tbl_entry, + expn_tbl, rule_pos)) { + ret = -EINVAL; + if (pthread_mutex_unlock(&nat_mutex) != 0) + goto mutex_unlock_error; + goto fail; + } + + ipa_nati_del_dead_ipv4_head_nodes(tbl_indx); + + /* Reset rule_id_array entry */ + ipv4_nat_cache.ip4_tbl[tbl_indx].rule_id_array[rule_hdl-1] = + IPA_NAT_INVALID_NAT_ENTRY; + +#ifdef NAT_DUMP + IPADBG("Dumping Table after deleting rule\n"); + ipa_nat_dump_ipv4_table(tbl_hdl); +#endif + + if (pthread_mutex_unlock(&nat_mutex) != 0) { + ret = -1; + goto mutex_unlock_error; + } + + return 0; + +mutex_lock_error: + IPAERR("unable to lock the nat mutex\n"); + return ret; + +mutex_unlock_error: + IPAERR("unable to unlock the nat mutex\n"); + +fail: + return ret; +} + +void ReorderCmds(struct ipa_ioc_nat_dma_cmd *cmd, int size) +{ + int indx_tbl_start = 0, cnt, cnt1; + struct ipa_ioc_nat_dma_cmd *tmp; + + IPADBG("called ReorderCmds() with entries :%d\n", cmd->entries); + + for (cnt = 0; cnt < cmd->entries; cnt++) { + if (cmd->dma[cnt].base_addr == IPA_NAT_INDX_TBL || + cmd->dma[cnt].base_addr == IPA_NAT_INDEX_EXPN_TBL) { + indx_tbl_start = cnt; + break; + } + } + + if (indx_tbl_start == 0) { + IPADBG("Reorder not needed\n"); + return; + } + + tmp = (struct ipa_ioc_nat_dma_cmd *)malloc(size); + if (tmp == NULL) { + IPAERR("unable to allocate memory\n"); + return; + } + + cnt1 = 0; + tmp->entries = cmd->entries; + for (cnt = indx_tbl_start; cnt < cmd->entries; cnt++) { + tmp->dma[cnt1] = cmd->dma[cnt]; + cnt1++; + } + + for (cnt = 0; cnt < indx_tbl_start; cnt++) { + tmp->dma[cnt1] = cmd->dma[cnt]; + cnt1++; + } + + memset(cmd, 0, size); + memcpy(cmd, tmp, size); + free(tmp); + + return; +} + +int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx, + uint16_t cur_tbl_entry, + uint8_t expn_tbl, + del_type rule_pos) +{ + +#define MAX_DMA_ENTRIES_FOR_DEL 3 + + struct ipa_nat_ip4_table_cache *cache_ptr; + struct ipa_nat_indx_tbl_rule *indx_tbl_ptr; + struct ipa_nat_rule *tbl_ptr; + int ret = 0, size = 0; + + uint16_t indx_tbl_entry = IPA_NAT_INVALID_NAT_ENTRY; + del_type indx_rule_pos; + + struct ipa_ioc_nat_dma_cmd *cmd; + uint8_t no_of_cmds = 0; + + uint16_t prev_entry = IPA_NAT_INVALID_NAT_ENTRY; + uint16_t next_entry = IPA_NAT_INVALID_NAT_ENTRY; + uint16_t indx_next_entry = IPA_NAT_INVALID_NAT_ENTRY; + uint16_t indx_next_next_entry = IPA_NAT_INVALID_NAT_ENTRY; + uint16_t table_entry; + + size = sizeof(struct ipa_ioc_nat_dma_cmd)+ + (MAX_DMA_ENTRIES_FOR_DEL * sizeof(struct ipa_ioc_nat_dma_one)); + + cmd = (struct ipa_ioc_nat_dma_cmd *)malloc(size); + if (NULL == cmd) { + IPAERR("unable to allocate memory\n"); + return -ENOMEM; + } + + cache_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx]; + if (!expn_tbl) { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr; + } else { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr; + } + + + if (!Read16BitFieldValue(tbl_ptr[cur_tbl_entry].ip_cksm_enbl, + ENABLE_FIELD)) { + IPAERR("Deleting invalid(not enabled) rule\n"); + ret = -EINVAL; + goto fail; + } + + indx_tbl_entry = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params, + SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD); + + /* ================================================ + Base Table rule Deletion + ================================================*/ + /* Just delete the current rule by disabling the flag field */ + if (IPA_NAT_DEL_TYPE_ONLY_ONE == rule_pos) { + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL; + cmd->dma[no_of_cmds].data = IPA_NAT_FLAG_DISABLE_BIT_MASK; + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, + cur_tbl_entry); + cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET; + } + + /* Just update the protocol field to invalid */ + else if (IPA_NAT_DEL_TYPE_HEAD == rule_pos) { + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL; + cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_PROTO_FIELD_VALUE; + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, + cur_tbl_entry); + cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_PROTO_FIELD_OFFSET; + + IPADBG("writing invalid proto: 0x%x\n", cmd->dma[no_of_cmds].data); + } + + /* + Update the previous entry of next_index field value + with current entry next_index field value + */ + else if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos) { + prev_entry = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params, + SW_SPEC_PARAM_PREV_INDEX_FIELD); + + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD); + + cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL; + if (prev_entry >= cache_ptr->table_entries) { + cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL; + prev_entry -= cache_ptr->table_entries; + } + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, prev_entry); + + cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET; + } + + /* + Reset the previous entry of next_index field with 0 + */ + else if (IPA_NAT_DEL_TYPE_LAST == rule_pos) { + prev_entry = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params, + SW_SPEC_PARAM_PREV_INDEX_FIELD); + + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY; + + cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL; + if (prev_entry >= cache_ptr->table_entries) { + cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL; + prev_entry -= cache_ptr->table_entries; + } + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, prev_entry); + + cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET; + } + + /* ================================================ + Base Table rule Deletion End + ================================================*/ + + /* ================================================ + Index Table rule Deletion + ================================================*/ + ipa_nati_find_index_rule_pos(cache_ptr, + indx_tbl_entry, + &indx_rule_pos); + IPADBG("Index table entry: 0x%x\n", indx_tbl_entry); + IPADBG("and position: %d\n", indx_rule_pos); + if (indx_tbl_entry >= cache_ptr->table_entries) { + indx_tbl_entry -= cache_ptr->table_entries; + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr; + } else { + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr; + } + + /* Just delete the current rule by resetting nat_table_index field to 0 */ + if (IPA_NAT_DEL_TYPE_ONLY_ONE == indx_rule_pos) { + no_of_cmds++; + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL; + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY; + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_index_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, + indx_tbl_entry); + + cmd->dma[no_of_cmds].offset += + IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET; + } + + /* copy the next entry values to current entry */ + else if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos) { + next_entry = + Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + next_entry -= cache_ptr->table_entries; + + no_of_cmds++; + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL; + cmd->dma[no_of_cmds].table_index = tbl_indx; + + /* Copy the nat_table_index field value of next entry */ + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr; + cmd->dma[no_of_cmds].data = + Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD); + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_index_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, + indx_tbl_entry); + + cmd->dma[no_of_cmds].offset += + IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET; + + /* Copy the next_index field value of next entry */ + no_of_cmds++; + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL; + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = + Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_index_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, indx_tbl_entry); + + cmd->dma[no_of_cmds].offset += + IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET; + indx_next_entry = next_entry; + } + + /* + Update the previous entry of next_index field value + with current entry next_index field value + */ + else if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos) { + prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index; + + no_of_cmds++; + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = + Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL; + if (prev_entry >= cache_ptr->table_entries) { + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL; + prev_entry -= cache_ptr->table_entries; + } + + IPADBG("prev_entry: %d update with cur next_index: %d\n", + prev_entry, cmd->dma[no_of_cmds].data); + IPADBG("prev_entry: %d exist in table_type:%d\n", + prev_entry, cmd->dma[no_of_cmds].base_addr); + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_index_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, prev_entry); + + cmd->dma[no_of_cmds].offset += + IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET; + } + + /* Reset the previous entry next_index field with 0 */ + else if (IPA_NAT_DEL_TYPE_LAST == indx_rule_pos) { + prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index; + + no_of_cmds++; + cmd->dma[no_of_cmds].table_index = tbl_indx; + cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY; + + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL; + if (prev_entry >= cache_ptr->table_entries) { + cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL; + prev_entry -= cache_ptr->table_entries; + } + + IPADBG("Reseting prev_entry: %d next_index\n", prev_entry); + IPADBG("prev_entry: %d exist in table_type:%d\n", + prev_entry, cmd->dma[no_of_cmds].base_addr); + + cmd->dma[no_of_cmds].offset = + ipa_nati_get_index_entry_offset(cache_ptr, + cmd->dma[no_of_cmds].base_addr, prev_entry); + + cmd->dma[no_of_cmds].offset += + IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET; + } + + /* ================================================ + Index Table rule Deletion End + ================================================*/ + cmd->entries = no_of_cmds + 1; + + if (cmd->entries > 1) { + ReorderCmds(cmd, size); + } + if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd)) { + perror("ipa_nati_post_del_dma_cmd(): ioctl error value"); + IPAERR("unable to post cmd\n"); + IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd); + ret = -EIO; + goto fail; + } + + /* if entry exist in IPA_NAT_DEL_TYPE_MIDDLE of list + Update the previous entry in sw specific parameters + */ + if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos) { + /* Retrieve the current entry prev_entry value */ + prev_entry = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params, + SW_SPEC_PARAM_PREV_INDEX_FIELD); + + /* Retrieve the next entry */ + next_entry = + Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD); + + next_entry -= cache_ptr->table_entries; + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr; + + /* copy the current entry prev_entry value to next entry*/ + UpdateSwSpecParams(&tbl_ptr[next_entry], + IPA_NAT_SW_PARAM_PREV_INDX_BYTE, + prev_entry); + } + + /* Reset the other field values of current delete entry + In case of IPA_NAT_DEL_TYPE_HEAD, don't reset */ + if (IPA_NAT_DEL_TYPE_HEAD != rule_pos) { + memset(&tbl_ptr[cur_tbl_entry], 0, sizeof(struct ipa_nat_rule)); + } + + if (indx_rule_pos == IPA_NAT_DEL_TYPE_HEAD) { + + /* Update next next entry previous value to current + entry as we moved the next entry values + to current entry */ + indx_next_next_entry = + Read16BitFieldValue(indx_tbl_ptr[indx_next_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + if (indx_next_next_entry != 0 && + indx_next_next_entry >= cache_ptr->table_entries) { + + IPADBG("Next Next entry: %d\n", indx_next_next_entry); + indx_next_next_entry -= cache_ptr->table_entries; + + IPADBG("Updating entry: %d prev index to: %d\n", + indx_next_next_entry, indx_tbl_entry); + cache_ptr->index_expn_table_meta[indx_next_next_entry].prev_index = + indx_tbl_entry; + } + + /* Now reset the next entry as we copied + the next entry to current entry */ + IPADBG("Resetting, index table entry(Proper): %d\n", + (cache_ptr->table_entries + indx_next_entry)); + + /* This resets both table entry and next index values */ + indx_tbl_ptr[indx_next_entry].tbl_entry_nxt_indx = 0; + + /* + In case of IPA_NAT_DEL_TYPE_HEAD, update the sw specific parameters + (index table entry) of base table entry + */ + indx_tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr; + table_entry = + Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD); + + if (table_entry >= cache_ptr->table_entries) { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr; + table_entry -= cache_ptr->table_entries; + } else { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr; + } + + UpdateSwSpecParams(&tbl_ptr[table_entry], + IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE, + indx_tbl_entry); + } else { + /* Update the prev_entry value (in index_expn_table_meta) + for the next_entry in list with current entry prev_entry value + */ + if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos) { + next_entry = + Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED); + + if (next_entry >= cache_ptr->table_entries) { + next_entry -= cache_ptr->table_entries; + } + + cache_ptr->index_expn_table_meta[next_entry].prev_index = + cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index; + + cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index = + IPA_NAT_INVALID_NAT_ENTRY; + } + + IPADBG("At, indx_tbl_entry value: %d\n", indx_tbl_entry); + IPADBG("At, indx_tbl_entry member address: %p\n", + &indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx); + + indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx = 0; + + } + +fail: + free(cmd); + + return ret; +} + +void ipa_nati_find_index_rule_pos( + struct ipa_nat_ip4_table_cache *cache_ptr, + uint16_t tbl_entry, + del_type *rule_pos) +{ + struct ipa_nat_indx_tbl_rule *tbl_ptr; + + if (tbl_entry >= cache_ptr->table_entries) { + tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr; + + tbl_entry -= cache_ptr->table_entries; + if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) { + *rule_pos = IPA_NAT_DEL_TYPE_LAST; + } else { + *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE; + } + } else { + tbl_ptr = + (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr; + + if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx, + INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY) { + *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE; + } else { + *rule_pos = IPA_NAT_DEL_TYPE_HEAD; + } + } +} + +void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr, + uint8_t expn_tbl, + uint16_t tbl_entry, + del_type *rule_pos) +{ + struct ipa_nat_rule *tbl_ptr; + + if (expn_tbl) { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr; + if (Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) { + *rule_pos = IPA_NAT_DEL_TYPE_LAST; + } else { + *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE; + } + } else { + tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr; + if (Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port, + NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) { + *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE; + } else { + *rule_pos = IPA_NAT_DEL_TYPE_HEAD; + } + } +} + +void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx) +{ + struct ipa_nat_rule *tbl_ptr; + uint16_t cnt; + + tbl_ptr = + (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr; + + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries; + cnt++) { + + if (Read8BitFieldValue(tbl_ptr[cnt].ts_proto, + PROTOCOL_FIELD) == IPA_NAT_INVALID_PROTO_FIELD_CMP + && + Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port, + NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY) { + /* Delete the IPA_NAT_DEL_TYPE_HEAD node */ + IPADBG("deleting the dead node 0x%x\n", cnt); + memset(&tbl_ptr[cnt], 0, sizeof(struct ipa_nat_rule)); + } + } /* end of for loop */ + + return; +} + + +/* ======================================================== + Debug functions + ========================================================*/ +#ifdef NAT_DUMP +void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl) +{ + struct ipa_nat_rule *tbl_ptr; + struct ipa_nat_indx_tbl_rule *indx_tbl_ptr; + int cnt; + uint8_t atl_one = 0; + + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || + tbl_hdl > IPA_NAT_MAX_IP4_TBLS) { + IPAERR("invalid table handle passed\n"); + return; + } + + /* Print ipv4 rules */ + IPADBG("Dumping ipv4 active rules:\n"); + tbl_ptr = (struct ipa_nat_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_rules_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries; + cnt++) { + if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl, + ENABLE_FIELD)) { + atl_one = 1; + ipa_nati_print_rule(&tbl_ptr[cnt], cnt); + } + } + if (!atl_one) { + IPADBG("No active base rules, total: %d\n", + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries); + } + atl_one = 0; + + /* Print ipv4 expansion rules */ + IPADBG("Dumping ipv4 active expansion rules:\n"); + tbl_ptr = (struct ipa_nat_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_expn_rules_addr; + for (cnt = 0; + cnt <= ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries; + cnt++) { + if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl, + ENABLE_FIELD)) { + atl_one = 1; + ipa_nati_print_rule(&tbl_ptr[cnt], + (cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries)); + } + } + if (!atl_one) { + IPADBG("No active base expansion rules, total: %d\n", + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries); + } + atl_one = 0; + + /* Print ipv4 index rules */ + IPADBG("Dumping ipv4 index active rules:\n"); + indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries; + cnt++) { + if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + atl_one = 1; + ipa_nati_print_index_rule(&indx_tbl_ptr[cnt], cnt, 0); + } + } + if (!atl_one) { + IPADBG("No active index table rules, total:%d\n", + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries); + } + atl_one = 0; + + + /* Print ipv4 index expansion rules */ + IPADBG("Dumping ipv4 index expansion active rules:\n"); + indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_expn_addr; + for (cnt = 0; + cnt <= ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries; + cnt++) { + if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + atl_one = 1; + ipa_nati_print_index_rule(&indx_tbl_ptr[cnt], + (cnt + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries), + ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_expn_table_meta[cnt].prev_index); + } + } + if (!atl_one) { + IPADBG("No active index expansion rules, total:%d\n", + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries); + } + atl_one = 0; + +} + +void ipa_nati_print_rule( + struct ipa_nat_rule *param, + uint32_t rule_id) +{ + struct ipa_nat_sw_rule sw_rule; + memcpy(&sw_rule, param, sizeof(sw_rule)); + uint32_t ip_addr; + + IPADUMP("rule-id:%d ", rule_id); + ip_addr = sw_rule.target_ip; + IPADUMP("Trgt-IP:%d.%d.%d.%d ", + ((ip_addr & 0xFF000000) >> 24), ((ip_addr & 0x00FF0000) >> 16), + ((ip_addr & 0x0000FF00) >> 8), ((ip_addr & 0x000000FF))); + + IPADUMP("Trgt-Port:%d Priv-Port:%d ", sw_rule.target_port, sw_rule.private_port); + + ip_addr = sw_rule.private_ip; + IPADUMP("Priv-IP:%d.%d.%d.%d ", + ((ip_addr & 0xFF000000) >> 24), ((ip_addr & 0x00FF0000) >> 16), + ((ip_addr & 0x0000FF00) >> 8), ((ip_addr & 0x000000FF))); + + IPADUMP("Pub-Port:%d Nxt-indx:%d ", sw_rule.public_port, sw_rule.next_index); + IPADUMP("IP-cksm-delta:0x%x En-bit:0x%x ", sw_rule.ip_chksum, sw_rule.enable); + IPADUMP("TS:0x%x Proto:0x%x ", sw_rule.time_stamp, sw_rule.protocol); + IPADUMP("Prv-indx:%d indx_tbl_entry:%d ", sw_rule.prev_index, sw_rule.indx_tbl_entry); + IPADUMP("Tcp-udp-cksum-delta:0x%x", sw_rule.tcp_udp_chksum); + IPADUMP("\n"); + return; +} + +void ipa_nati_print_index_rule( + struct ipa_nat_indx_tbl_rule *param, + uint32_t rule_id, uint16_t prev_indx) +{ + struct ipa_nat_sw_indx_tbl_rule sw_rule; + memcpy(&sw_rule, param, sizeof(sw_rule)); + + IPADUMP("rule-id:%d Table_entry:%d Next_index:%d, prev_indx:%d", + rule_id, sw_rule.tbl_entry, sw_rule.next_index, prev_indx); + IPADUMP("\n"); + return; +} + +int ipa_nati_query_nat_rules( + uint32_t tbl_hdl, + nat_table_type tbl_type) +{ + struct ipa_nat_rule *tbl_ptr; + struct ipa_nat_indx_tbl_rule *indx_tbl_ptr; + int cnt = 0, ret = 0; + + if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl || + tbl_hdl > IPA_NAT_MAX_IP4_TBLS) { + IPAERR("invalid table handle passed\n"); + return ret; + } + + /* Print ipv4 rules */ + if (tbl_type == IPA_NAT_BASE_TBL) { + IPADBG("Counting ipv4 active rules:\n"); + tbl_ptr = (struct ipa_nat_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].ipv4_rules_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries; + cnt++) { + if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl, + ENABLE_FIELD)) { + ret++; + } + } + if (!ret) { + IPADBG("No active base rules\n"); + } + + IPADBG("Number of active base rules: %d\n", ret); + } + + /* Print ipv4 expansion rules */ + if (tbl_type == IPA_NAT_EXPN_TBL) { + IPADBG("Counting ipv4 active expansion rules:\n"); + tbl_ptr = (struct ipa_nat_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].ipv4_expn_rules_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries; + cnt++) { + if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl, + ENABLE_FIELD)) { + ret++; + } + } + if (!ret) { + IPADBG("No active base expansion rules\n"); + } + + IPADBG("Number of active base expansion rules: %d\n", ret); + } + + /* Print ipv4 index rules */ + if (tbl_type == IPA_NAT_INDX_TBL) { + IPADBG("Counting ipv4 index active rules:\n"); + indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].index_table_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].table_entries; + cnt++) { + if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + ret++; + } + } + if (!ret) { + IPADBG("No active index table rules\n"); + } + + IPADBG("Number of active index table rules: %d\n", ret); + } + + /* Print ipv4 index expansion rules */ + if (tbl_type == IPA_NAT_INDEX_EXPN_TBL) { + IPADBG("Counting ipv4 index expansion active rules:\n"); + indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *) + ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].index_table_expn_addr; + for (cnt = 0; + cnt < ipv4_nat_cache.ip4_tbl[tbl_hdl - 1].expn_table_entries; + cnt++) { + if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx, + INDX_TBL_TBL_ENTRY_FIELD)) { + ret++; + } + } + + if (!ret) + IPADBG("No active index expansion rules\n"); + + IPADBG("Number of active index expansion rules: %d\n", ret); + } + + return ret; +} +#endif diff --git a/data-ipa-cfg-mgr/ipanat/src/ipa_nat_logi.c b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_logi.c new file mode 100644 index 0000000..b829b78 --- /dev/null +++ b/data-ipa-cfg-mgr/ipanat/src/ipa_nat_logi.c @@ -0,0 +1,49 @@ +/* +Copyright (c) 2013, 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. +*/ +/*! + @file + IPACM_log.cpp + + @brief + This file implements the IPAM log functionality. + + @Author + Skylar Chang + +*/ +#include "ipa_nat_logi.h" +#include <stdlib.h> +#include <unistd.h> + +void log_nat_message(char *msg) +{ + return; +} + + |