summaryrefslogtreecommitdiff
path: root/ipanat
diff options
context:
space:
mode:
authorRavi Gummadidala <rgummadi@codeaurora.org>2013-01-23 20:13:27 -0800
committerRavi Gummadidala <rgummadi@codeaurora.org>2013-02-28 16:04:09 -0800
commit5dcfae28ef76dadd1873bfcfb309c516dae24900 (patch)
tree911a8cec67b29adf2f93f29719183eea4e75a832 /ipanat
parentca61ebfc9f68110b3723efaad039d5aa2f8d21af (diff)
downloadipacfg-mgr-5dcfae28ef76dadd1873bfcfb309c516dae24900.tar.gz
IPA configuration manager daemon and IPA NAT library.
These are user-space components which configure IPA (Internet Protocol Accelerator) HW using the services provided by the IPA driver (running in kernel space). NAT stands for Network Address Translation. This is the initial commit of these components. Change-Id: I0934f54c36a7134af143e4f1cd9fbb0682df52d0
Diffstat (limited to 'ipanat')
-rw-r--r--ipanat/inc/ipa_nat_drv.h118
-rw-r--r--ipanat/inc/ipa_nat_drvi.h474
-rw-r--r--ipanat/inc/ipa_nat_logi.h79
-rw-r--r--ipanat/src/Makefile.am20
-rw-r--r--ipanat/src/ipa_nat_drv.c177
-rw-r--r--ipanat/src/ipa_nat_drvi.c2387
-rw-r--r--ipanat/src/ipa_nat_logi.c68
7 files changed, 3323 insertions, 0 deletions
diff --git a/ipanat/inc/ipa_nat_drv.h b/ipanat/inc/ipa_nat_drv.h
new file mode 100644
index 0000000..cda63f1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drv.h
@@ -0,0 +1,118 @@
+/*
+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.
+*/
+
+#include "string.h" /* memset */
+#include "stdlib.h" /* free, malloc */
+#include "stdint.h" /* uint32_t */
+
+/**
+ * struct ipa_nat_ipv4_rule - To hold ipv4 nat rule
+ * @target_ip: destination ip address
+ * @private_ip: private ip address
+ * @target_port: destination port
+ * @private_port: private port
+ * @protocol: protocol of rule (tcp/udp)
+ */
+typedef struct
+{
+ uint32_t target_ip;
+ uint32_t private_ip;
+ uint16_t target_port;
+ uint16_t private_port;
+ uint16_t public_port;
+ uint8_t protocol;
+
+}ipa_nat_ipv4_rule;
+
+/**
+ * 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 *table_handle);
+
+/**
+ * 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 table_handle);
+
+/**
+ * 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 table_handle,
+ const ipa_nat_ipv4_rule *rule,
+ uint32_t *rule_handle);
+
+/**
+ * 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 table_handle,
+ uint32_t rule_handle);
+
+
+/**
+ * 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 table_handle,
+ uint32_t rule_handle,
+ uint32_t *time_stamp);
+
diff --git a/ipanat/inc/ipa_nat_drvi.h b/ipanat/inc/ipa_nat_drvi.h
new file mode 100644
index 0000000..9b56cf1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drvi.h
@@ -0,0 +1,474 @@
+/*
+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.
+*/
+
+#ifndef IPA_NAT_DRVI_H
+#define IPA_NAT_DRVI_H
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/msm_ipa.h>
+#include <netinet/in.h>
+#include <sys/inotify.h>
+
+#include "ipa_nat_logi.h"
+
+#define NAT_DUMP
+//#define IPADBG(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+//#define IPAERR(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+
+
+/*======= IMPLEMENTATION related data structures and functions ======= */
+#ifdef IPA_ON_R3PC
+#define NAT_MMAP_MEM_SIZE (2 * 1024UL * 1024UL - 1)
+#endif
+
+#define IPA_DEV_NAME "/dev/ipa"
+#define NAT_DEV_DIR "/dev"
+#define NAT_DEV_NAME "ipaNatTable"
+#define NAT_DEV_FULL_NAME "/dev/ipaNatTable"
+
+#define IPA_NAT_TABLE_VALID 1
+#define IPA_NAT_MAX_IP4_TBLS 1
+#define IPA_NAT_BASE_TABLE_PERCENTAGE .8
+#define IPA_NAT_EXPANSION_TABLE_PERCENTAGE .2
+
+#define IPA_NAT_NUM_OF_BASE_TABLES 2
+#define IPA_NAT_UNUSED_BASE_ENTRIES 2
+
+#define IPA_NAT_RULE_FLAG_FIELD_OFFSET 18
+#define IPA_NAT_RULE_NEXT_FIELD_OFFSET 8
+#define IPA_NAT_RULE_PROTO_FIELD_OFFSET 22
+
+#define IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET 2
+#define IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET 0
+
+#define IPA_NAT_RULE_FLAG_FIELD_SIZE 2
+#define IPA_NAT_RULE_NEXTFIELD_FIELD_SIZE 2
+
+#define IPA_NAT_FLAG_ENABLE_BIT_MASK 0x8000
+#define IPA_NAT_FLAG_DISABLE_BIT_MASK 0x0000
+
+#define IPA_NAT_FLAG_ENABLE_BIT 1
+#define IPA_NAT_FLAG_DISABLE_BIT 0
+
+#define IPA_NAT_INVALID_PROTO_FIELD_VALUE 0xFF00
+#define IPA_NAT_INVALID_PROTO_FIELD_CMP 0xFF
+
+#define IPA_NAT_INVALID_INDEX 0xFF
+#define IPA_NAT_INVALID_NAT_ENTRY 0x0
+
+#define INDX_TBL_ENTRY_SIZE_IN_BITS 16
+
+/* ----------- Rule id -----------------------
+
+ ------------------------------------------------
+ | 3bits | 12 bits | 1 bit |
+ ------------------------------------------------
+ | reserved | index into table | 0 - base |
+ | | | 1 - expansion |
+ ------------------------------------------------
+
+*/
+#define IPA_NAT_RULE_HDL_TBL_TYPE_BITS 0x1
+#define IPA_NAT_RULE_HDL_TBL_TYPE_MASK 0x1
+
+/* ----------- sw specif parameter -----
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+-----------------------------------------*/
+#define IPA_NAT_SW_PARAM_PREV_INDX_BYTE 0
+#define IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE 1
+
+typedef enum
+{
+ IPA_NAT_BASE_TBL = 0,
+ IPA_NAT_EXPN_TBL = 1,
+ IPA_NAT_INDX_TBL = 2,
+ IPA_NAT_INDEX_EXPN_TBL = 3,
+}nat_table_type;
+
+typedef enum
+{
+ NEXT_INDEX_FIELD,
+ PUBLIC_PORT_FILED,
+ PRIVATE_PORT_FIELD,
+ TARGET_PORT_FIELD,
+ IP_CHKSUM_FIELD,
+ ENABLE_FIELD,
+ TIME_STAMP_FIELD,
+ PROTOCOL_FIELD,
+ TCP_UDP_CHKSUM_FIELD,
+ SW_SPEC_PARAM_PREV_INDEX_FIELD,
+ SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD,
+ INDX_TBL_TBL_ENTRY_FIELD,
+ INDX_TBL_NEXT_INDEX_FILED
+
+}ipa_nat_rule_field_type;
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | Public Port(2B) | Next Index(2B) |
+ ---------------------------------------------
+*/
+typedef struct
+{
+ uint32_t next_index:16;
+ uint32_t public_port:16;
+}next_index_pub_port;
+
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | Flags(2B) | IP check sum Diff(2B)|
+ |EN|FIN|Resv | | |
+ ---------------------------------------------
+*/
+typedef struct
+{
+ uint32_t ip_chksum:16;
+ uint32_t rsvd1:14;
+ uint32_t redirect:1;
+ uint32_t enable:1;
+}ipcksum_enbl;
+
+
+/*
+ ---------------------------------------
+ | 7 | 6 | 5 | 4 |
+ ---------------------------------------
+ | Proto | TimeStamp(3B) |
+ | (1B) | |
+ ---------------------------------------
+*/
+typedef struct
+{
+ uint32_t time_stamp:24;
+ uint32_t protocol:8;
+}time_stamp_proto;
+
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | next_index | Table entry |
+ ----------------------------------------------
+*/
+typedef struct {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+}tbl_ent_nxt_indx;
+
+/*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+--------------------------------------------------*/
+typedef struct {
+ uint16_t prev_index;
+ uint16_t index_table_entry;
+}sw_spec_params;
+
+/*------------------------ NAT Table Entry ---------------------------------------
+
+ -----------------------------------------------------------------------------------
+ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ -----------------------------------------------------------------------------------
+ | Target IP(4B) | Private IP(4B) |
+ -----------------------------------------------------------------------------------
+ |Target Port(2B) | Private Port(2B) | Public Port(2B) | Next Index(2B) |
+ -----------------------------------------------------------------------------------
+ | Proto | TimeStamp(3B) | Flags(2B) | IP check sum Diff(2B)|
+ | (1B) | |EN|FIN|Resv | | |
+ -----------------------------------------------------------------------------------
+ | TCP/UDP checksum | Reserved(2B) | SW Specific Parameters(4B) |
+ | diff (2B) | |
+ -----------------------------------------------------------------------------------
+
+ Dont change below structure definition.
+ It should be same as above(little endian order)
+ -------------------------------------------------------------------------------*/
+struct ipa_nat_rule {
+ uint64_t private_ip:32;
+ uint64_t target_ip:32;
+
+ uint64_t nxt_indx_pub_port:32;
+ uint64_t private_port:16;
+ uint64_t target_port:16;
+
+ uint64_t ip_cksm_enbl:32;
+ uint64_t ts_proto:32;
+
+ /*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+ --------------------------------------------------*/
+ uint64_t sw_spec_params:32;
+
+ uint64_t rsvd2:16;
+ uint64_t tcp_udp_chksum:16;
+
+};
+
+struct ipa_nat_sw_rule {
+ uint64_t private_ip:32;
+ uint64_t target_ip:32;
+
+ uint64_t next_index:16;
+ uint64_t public_port:16;
+ uint64_t private_port:16;
+ uint64_t target_port:16;
+
+ uint64_t ip_chksum:16;
+ uint64_t rsvd1:14;
+ uint64_t redirect:1;
+ uint64_t enable:1;
+ uint64_t time_stamp:24;
+ uint64_t protocol:8;
+
+ /*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+ --------------------------------------------------*/
+ uint64_t prev_index:16;
+ uint64_t indx_tbl_entry:16;
+ uint64_t rsvd2:16;
+ uint64_t tcp_udp_chksum:16;
+
+};
+#define IPA_NAT_TABLE_ENTRY_SIZE 32
+#define IPA_NAT_INDEX_TABLE_ENTRY_SIZE 4
+
+struct ipa_nat_indx_tbl_rule {
+ uint32_t tbl_entry_nxt_indx;
+};
+
+struct ipa_nat_sw_indx_tbl_rule {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+};
+
+struct ipa_nat_indx_tbl_meta_info {
+ uint16_t prev_index;
+};
+
+struct ipa_nat_ip4_table_cache {
+ uint8_t valid;
+ uint32_t public_addr;
+
+ int nat_fd;
+ int size;
+ uint32_t tbl_addr_offset;
+ char table_name[IPA_RESOURCE_NAME_MAX];
+
+ char *ipv4_rules_addr;
+ char *index_table_addr;
+ uint16_t table_entries;
+
+ char *ipv4_expn_rules_addr;
+ char *index_table_expn_addr;
+ uint16_t expn_table_entries;
+
+ struct ipa_nat_indx_tbl_meta_info *index_expn_table_meta;
+
+ uint16_t *rule_id_array;
+#ifdef IPA_ON_R3PC
+ uint32_t mmap_offset;
+#endif
+};
+
+struct ipa_nat_cache {
+ struct ipa_nat_ip4_table_cache ip4_tbl[IPA_NAT_MAX_IP4_TBLS];
+ int ipa_fd;
+ uint8_t table_cnt;
+};
+
+struct ipa_nat_indx_tbl_sw_rule {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+ uint16_t prev_index;
+};
+
+typedef enum
+{
+ IPA_NAT_DEL_TYPE_ONLY_ONE,
+ IPA_NAT_DEL_TYPE_HEAD,
+ IPA_NAT_DEL_TYPE_MIDDLE,
+ IPA_NAT_DEL_TYPE_LAST,
+}del_type;
+
+/**
+ * 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_hdl,
+ uint16_t rule_hdl,
+ uint8_t *expn_tbl,
+ uint16_t *tbl_entry);
+
+/**
+ * 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);
+
+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);
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+ nat_table_type tbl_type,
+ uint16_t tbl_entry);
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+ uint16_t number_of_entries,
+ uint32_t *table_hanle);
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+ struct ipa_ioc_nat_alloc_mem *mem,
+ uint16_t *tbl_entries, uint16_t *expn_tbl_entries);
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *,
+ uint32_t public_ip_addr,
+ uint16_t tbl_entries,
+ uint16_t expn_tbl_entries);
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_reset_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index);
+
+int ipa_nati_query_timestamp(uint32_t tbl_hdl,
+ uint32_t rule_hdl,
+ uint32_t *time_stamp);
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule);
+
+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);
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+ uint16_t size);
+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);
+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);
+uint16_t ipa_nati_index_expn_get_free_entry(struct ipa_nat_indx_tbl_rule *tbl,
+ uint16_t size);
+
+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);
+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);
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+ nat_table_type tbl_type,
+ uint16_t value,
+ uint32_t offset);
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+ uint16_t entry);
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+ uint32_t rule_hdl);
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+ uint16_t tbl_entry,
+ uint8_t expn_tbl,
+ del_type rule_pos);
+void ipa_nati_find_index_rule_pos(
+ struct ipa_nat_ip4_table_cache *cache_ptr,
+ uint16_t tbl_entry,
+ del_type *rule_pos);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+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);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+
+
+/* ========================================================
+ Debug functions
+ ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nati_print_rule(struct ipa_nat_rule *rule, uint32_t rule_id);
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl);
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+#endif
+
+#endif /* #ifndef IPA_NAT_DRVI_H */
diff --git a/ipanat/inc/ipa_nat_logi.h b/ipanat/inc/ipa_nat_logi.h
new file mode 100644
index 0000000..0ffa672
--- /dev/null
+++ b/ipanat/inc/ipa_nat_logi.h
@@ -0,0 +1,79 @@
+/*
+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
+ ipa_nat_logi.h
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+
+
+*/
+
+#ifndef IPA_NAT_LOGI_H
+#define IPA_NAT_LOGI_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define NAT_LOG_SIZE 200
+
+#define PERROR(fmt) printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+ perror(fmt);
+
+#define IPADBG(fmt, ...) {\
+ int n =0; \
+ n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() ", __FILE__, __LINE__, __FUNCTION__);\
+ snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ log_nat_message(nat_log_buf);\
+ }
+
+
+#define IPAERR(fmt, ...) {\
+ int n =0; \
+ n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() %s", __FILE__, __LINE__, __FUNCTION__, "Error:");\
+ snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ log_nat_message(nat_log_buf);\
+ }
+
+extern void log_nat_message(char *msg);
+extern char nat_log_buf[NAT_LOG_SIZE];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPA_NAT_LOGI_H */
diff --git a/ipanat/src/Makefile.am b/ipanat/src/Makefile.am
new file mode 100644
index 0000000..cf9fc3f
--- /dev/null
+++ b/ipanat/src/Makefile.am
@@ -0,0 +1,20 @@
+AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+AM_CFLAGS += -I./../inc -I$(WORKSPACE)/kernel/include
+
+c_sources = ipa_nat_drv.c \
+ ipa_nat_drvi.c \
+ ipa_nat_logi.c
+
+library_includedir = $(pkgincludedir)
+library_include_HEADERS = ./../inc/ipa_nat_drvi.h \
+ ./../inc/ipa_nat_drv.h \
+ ./../inc/ipa_nat_logi.h
+
+lib_LTLIBRARIES = libipanat.la
+libipanat_la_C = @C@
+libipanat_la_SOURCES = $(c_sources)
+libipanat_la_CFLAGS = $(AM_CFLAGS)
+libipanat_la_LDFLAGS = -shared -version-info 1:0:0
+
+
+
diff --git a/ipanat/src/ipa_nat_drv.c b/ipanat/src/ipa_nat_drv.c
new file mode 100644
index 0000000..68e2de8
--- /dev/null
+++ b/ipanat/src/ipa_nat_drv.c
@@ -0,0 +1,177 @@
+/*
+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.
+*/
+
+#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 -1;
+ }
+
+ ret = ipa_nati_add_ipv4_tbl(public_ip_addr,
+ number_of_entries,
+ tbl_hdl);
+ if (ret != 0)
+ {
+ IPAERR("unable to add table \n");
+ return -1;
+ }
+ 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 -1;
+ }
+ 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)
+{
+
+ 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 -1;
+ }
+ IPADBG("Passed Table handle: 0x%x\n", tbl_hdl);
+
+ *rule_hdl = ipa_nati_add_ipv4_rule(tbl_hdl, clnt_rule);
+ 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)
+{
+
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+ IPA_NAT_INVALID_NAT_ENTRY == rule_hdl)
+ {
+ IPAERR("invalide parameters\n");
+ return -1;
+ }
+ IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+ if (-1 == ipa_nati_del_ipv4_rule(tbl_hdl, rule_hdl))
+ {
+ IPAERR("unable to delete rule from hw \n");
+ return -1;
+ }
+
+ 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 -1;
+ }
+ 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);
+}
+
+
diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c
new file mode 100644
index 0000000..d542a88
--- /dev/null
+++ b/ipanat/src/ipa_nat_drvi.c
@@ -0,0 +1,2387 @@
+/*
+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.
+*/
+
+#include "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+
+struct ipa_nat_cache ipv4_nat_cache;
+
+/* ------------------------------------------
+ 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 = (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 *)&param;
+
+ 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 *)&param;
+
+ 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 *)&param;
+
+ switch (fld_type)
+ {
+
+ case TIME_STAMP_FIELD:
+ return ((time_stamp_proto *)temp)->time_stamp;
+
+ default:
+ IPAERR("Invalid Field type passed\n");
+ 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)
+{
+
+#define EVENT_SIZE (sizeof (struct inotify_event))
+#define FILE_NAME_LENGTH (sizeof(NAT_DEV_NAME)*2 + 1)
+#define BUF_LEN (EVENT_SIZE + FILE_NAME_LENGTH)
+
+ int length;
+ int wd;
+ char buffer[BUF_LEN];
+ int ret, inotify_fd;
+
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ {
+ perror("inotify_init");
+ return -1;
+ }
+
+ IPADBG("Waiting for nofications in dir %s\n", NAT_DEV_DIR);
+ wd = inotify_add_watch(inotify_fd,
+ NAT_DEV_DIR,
+ IN_CREATE);
+
+ 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 -1;
+ }
+ IPADBG("posted IPA_IOC_ALLOC_NAT_MEM to kernel successfully \n");
+
+ length = read(inotify_fd, buffer, BUF_LEN );
+
+ if (length < 0)
+ {
+ perror("inotify read");
+ return -1;
+ }
+
+ struct inotify_event *event = (struct inotify_event *)buffer;
+ if(event->len)
+ {
+ if(event->mask & IN_CREATE)
+ {
+ if( event->mask & IN_ISDIR)
+ {
+ IPADBG("The directory %s was created.\n", event->name);
+ }
+ else
+ {
+ IPADBG("The file %s was created.\n", event->name);
+ }
+ }
+ }
+
+ (void) inotify_rm_watch(inotify_fd, wd);
+ (void) close(inotify_fd);
+ 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 -1;
+ }
+
+ 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 -1;
+}
+
+/**
+ * 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
+ * @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 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);
+
+ 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)
+ {
+ /* 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
+ {
+ 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 cnt;
+}
+
+/**
+ * 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 -1;
+ }
+
+ /* 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 -1;
+ }
+
+ /* 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 -1;
+ }
+
+ ipa_nati_reset_tbl(tbl_indx);
+
+ /* 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 */
+ strcpy(mem->dev_name, NAT_DEV_NAME);
+
+ /* 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(-1 == GetNearest2Power(*table_entries, table_entries))
+ {
+ IPAERR("unable to calculate power of 2\n");
+ return -1;
+ }
+
+ *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);
+ mem->size += (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * total_entries);
+
+ 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 -1;
+ }
+ ipv4_nat_cache.ipa_fd = fd;
+ }
+
+ 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 */
+ strcpy(mem->dev_name, NAT_DEV_FULL_NAME);
+ 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 -1;
+ }
+
+ /* copy the nat table name */
+ strncpy(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(NULL == ipv4_rules_addr)
+ {
+ perror("unable to mmap the memory\n");
+ return -1;
+ }
+
+#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 -1;
+ }
+ 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 -1;
+ }
+ 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");
+ return -1;
+ }
+
+ /* 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");
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+ IPADBG("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--;
+
+ return 0;
+}
+
+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 -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;
+ }
+
+ *time_stamp = Read32BitFieldValue(tbl_ptr[tbl_entry].ts_proto,
+ TIME_STAMP_FIELD);
+ return 0;
+}
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule)
+{
+ 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;
+ uint32_t rule_hdl = 0;
+
+ memset(&sw_rule, 0, sizeof(sw_rule));
+ memset(&index_sw_rule, 0, sizeof(index_sw_rule));
+
+ /* Generate rule from client input */
+ if (-1 == 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 -1;
+ }
+
+ 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( -1 == ipa_nati_post_ipv4_dma_cmd((uint8_t)(tbl_hdl-1), new_entry))
+ {
+ IPAERR("unable to post dma command\n");
+ return -1;
+ }
+
+ /* 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 -1;
+ }
+
+#ifdef NAT_DUMP
+ ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+ return rule_hdl;
+}
+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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 -1;
+ }
+
+ 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 = tbl_ptr->public_addr;
+
+ 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;
+
+ /* 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->prev_index = 0;
+ sw_rule->indx_tbl_entry = 0;
+
+ new_entry = dst_hash(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;
+ }
+ /* check for more than one collision */
+ else
+ {
+ /* 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");
+ 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);
+ //prev = nxt_indx;
+
+ 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");
+ return IPA_NAT_INVALID_NAT_ENTRY;
+ }
+ new_entry += tbl_ptr->table_entries;
+
+ 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 -1;
+ }
+
+ 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 = -1;
+ 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);
+
+ /* 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");
+ return -1;
+ }
+
+ 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");
+ return -1;
+ }
+
+ ipa_nati_find_rule_pos(tbl_ptr, expn_tbl,
+ tbl_entry, &rule_pos);
+ IPADBG("rule_pos:%d\n", rule_pos);
+
+ if(0 != ipa_nati_post_del_dma_cmd(tbl_indx, tbl_entry,
+ expn_tbl, rule_pos))
+ {
+ return -1;
+ }
+
+ 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
+
+ return 0;
+}
+
+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++)
+ {
+ memcpy(&tmp->dma[cnt1], &cmd->dma[cnt],
+ sizeof(struct ipa_ioc_nat_dma_one));
+ cnt1++;
+ }
+
+ for (cnt = 0; cnt<indx_tbl_start; cnt++)
+ {
+ memcpy(&tmp->dma[cnt1], &cmd->dma[cnt],
+ sizeof(struct ipa_ioc_nat_dma_one));
+ 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 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 -1;
+ }
+
+ 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 = -1;
+ 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 */
+ 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
+ */
+ 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
+ */
+ 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 */
+ 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;
+ }
+
+ /*
+ Update the previous entry of next_index field value
+ with current entry next_index field value
+ */
+ 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;
+ }
+
+ 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 */
+ 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;
+ }
+
+ 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 = -1;
+ 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 (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos)
+ {
+ /* Reset the next entry to IPA_NAT_DEL_TYPE_HEAD as we copied
+ the next entry to IPA_NAT_DEL_TYPE_HEAD */
+ indx_tbl_ptr[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);
+ ipa_nati_dump_rule_buf(&tbl_ptr[cnt],
+ sizeof(struct ipa_nat_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active base rules\n");
+ }
+ 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))
+ {
+ ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+ ipa_nati_dump_rule_buf(&tbl_ptr[cnt],
+ sizeof(struct ipa_nat_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active base expansion rules\n");
+ }
+ 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))
+ {
+ ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt],
+ sizeof(struct ipa_nat_indx_tbl_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active index table rules\n");
+ }
+ 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))
+ {
+ ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt],
+ sizeof(struct ipa_nat_indx_tbl_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active index expansion rules\n");
+ }
+ atl_one = 0;
+
+}
+
+
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+ int cnt = 0;
+ uint8_t temp[IPA_NAT_TABLE_ENTRY_SIZE];
+ uint64_t *rule = NULL;
+
+ memcpy(&temp, param1, sizeof(temp));
+ rule = (uint64_t *)temp;
+
+ IPADBG("Address :%p, rule id: %d size: %d\n",
+ rule, rule_id, size);
+ for(; cnt<size; )
+ {
+ uint8_t *byte = (uint8_t *)rule;
+
+ IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+ IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[0], byte[1], byte[2], byte[3]);
+ IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[4], byte[5], byte[6], byte[7]);
+
+ cnt += 8;
+ rule++;
+ }
+
+ return;
+}
+
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+ int cnt = 0;
+ uint8_t temp[IPA_NAT_INDEX_TABLE_ENTRY_SIZE];
+ uint16_t *rule = NULL;
+
+ memcpy(&temp, param1, sizeof(temp));
+ rule = (uint16_t *)temp;
+
+ IPADBG("Address :%p, rule id: %d size: %d\n",
+ rule, rule_id, size);
+
+ for(; cnt<size; )
+ {
+ uint8_t *byte = (uint8_t *)rule;
+
+ IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+ IPADBG("%02x\t%02x\n", byte[0], byte[1]);
+ IPADBG("\n");
+
+ cnt += 2;
+ rule++;
+ }
+
+ return;
+}
+
+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));
+
+ IPADBG("Printing NAT Rule:%d at memory location:%p\n", rule_id, param);
+
+ IPADBG("Target IP: 0x%x Target Port: 0x%x\n",
+ sw_rule.target_ip, sw_rule.target_port);
+
+ IPADBG("Private IP: 0x%x Private Port: 0x%x\n",
+ sw_rule.private_ip, sw_rule.private_port);
+
+ IPADBG("Public Port: 0x%x Next index: 0x%x\n",
+ sw_rule.public_port, sw_rule.next_index);
+
+ IPADBG("IP ChkSum: 0x%x Enable bit: 0x%x\n",
+ sw_rule.ip_chksum, sw_rule.enable);
+
+ IPADBG("Time Stamp: 0x%x Protocol: 0x%x\n",
+ sw_rule.time_stamp, sw_rule.protocol);
+
+ IPADBG("Prev Index: 0x%x Next Index: 0x%x\n",
+ sw_rule.prev_index, sw_rule.next_index);
+
+ IPADBG("TCP UDP Chksum: 0x%x\n", sw_rule.tcp_udp_chksum);
+
+ return;
+}
+#endif
diff --git a/ipanat/src/ipa_nat_logi.c b/ipanat/src/ipa_nat_logi.c
new file mode 100644
index 0000000..11991c9
--- /dev/null
+++ b/ipanat/src/ipa_nat_logi.c
@@ -0,0 +1,68 @@
+/*
+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>
+
+#define NAT_FILE_NAME "/usr/ipanat_log.txt"
+
+static FILE *nat_fp = NULL;
+char nat_log_buf[NAT_LOG_SIZE];
+
+void log_nat_message(char *msg)
+{
+ printf("%s", msg);
+#if 0
+ if(nat_fp == NULL)
+ {
+ nat_fp = fopen(NAT_FILE_NAME, "wb+");
+ if(nat_fp == NULL)
+ {
+ printf("unable to open file\n");
+ return;
+ }
+ }
+
+ fprintf(nat_fp, msg);
+ fflush(nat_fp);
+#endif
+ return;
+}
+
+