ipacm : Add change to update NAT entries for embedded/tethered connections
Add change to read and process conntrack entries only when WAN is
up and add NAT entries accordingly when switch to tethered connections.
Change-Id: Iaa31a44684082802c03402cdd1faa393a7bc85f8
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
index 24a2c72..6cc4188 100644
--- a/ipacm/inc/IPACM_ConntrackListener.h
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -68,6 +68,7 @@
bool isCTReg;
bool isNatThreadStart;
bool WanUp;
+ bool isProcessCTDone;
NatApp *nat_inst;
int NatIfaceCnt;
@@ -77,6 +78,7 @@
uint32_t nonnat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
uint32_t sta_clnt_ipv4_addr[MAX_STA_CLNT_IFACES];
IPACM_Config *pConfig;
+ struct nf_conntrack **ct_entries;
#ifdef CT_OPT
IPACM_LanToLan *p_lan2lan;
#endif
@@ -104,6 +106,7 @@
char wan_ifname[IPA_IFACE_NAME_LEN];
uint32_t wan_ipaddr;
ipacm_wan_iface_type backhaul_mode;
+ bool isReadCTDone;
IPACM_ConntrackListener();
void event_callback(ipa_cm_event_id, void *data);
inline bool isWanUp()
@@ -116,6 +119,8 @@
void HandleSTAClientAddEvt(uint32_t);
void HandleSTAClientDelEvt(uint32_t);
int CreateConnTrackThreads(void);
+ void readConntrack(void);
+ void processConntrack(void);
};
extern IPACM_ConntrackListener *CtList;
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index a3cbba1..e60516e 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -105,6 +105,11 @@
#define NUM_IPV6_PREFIX_FLT_RULE 1
#define NUM_IPV6_PREFIX_MTU_RULE 1
+#define MAX_CONNTRACK_ENTRIES 100
+#define CT_ENTRIES_BUFFER_SIZE 8096
+#define LOOPBACK_MASK 0xFF000000
+#define LOOPBACK_ADDR 0x7F000000
+
/*---------------------------------------------------------------------------
Return values indicating error status
---------------------------------------------------------------------------*/
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index 8a2499c..24f95a3 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -421,6 +421,17 @@
unsigned subscrips = 0;
IPACMDBG("\n");
+ /* In Android we get conntrack handles once after tethering is enabled but we
+ loose connections info for embedded traffic if running before. So no NAT
+ entries are added for embedded traffic due to which we see NAT exception and
+ data takes S/W path which results in less throughput. Hence for embedded
+ traffic info, framework sends conntrack dump before providing handles. Here
+ reading ct entries before creating filter on Fd in order to have NAT entries
+ for both TCP/UDP embedded traffic. */
+ if(CtList != NULL && !CtList->isReadCTDone)
+ {
+ CtList->readConntrack();
+ }
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index e006393..fff6bfc 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -35,6 +35,7 @@
#include "IPACM_EvtDispatcher.h"
#include "IPACM_Iface.h"
#include "IPACM_Wan.h"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
IPACM_ConntrackListener::IPACM_ConntrackListener()
{
@@ -43,11 +44,14 @@
isNatThreadStart = false;
isCTReg = false;
WanUp = false;
+ isReadCTDone = false;
+ isProcessCTDone = false;
nat_inst = NatApp::GetInstance();
NatIfaceCnt = 0;
StaClntCnt = 0;
pNatIfaces = NULL;
+ ct_entries = NULL;
pConfig = IPACM_Config::GetInstance();;
memset(nat_iface_ipv4_addr, 0, sizeof(nat_iface_ipv4_addr));
@@ -97,6 +101,10 @@
IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
CreateConnTrackThreads();
TriggerWANUp(data);
+ if(isReadCTDone && !isProcessCTDone)
+ {
+ processConntrack();
+ }
break;
case IPA_HANDLE_WAN_DOWN:
@@ -1201,3 +1209,157 @@
nat_inst->FlushTempEntries(clnt_ip_addr, false);
return;
}
+
+bool isLocalHostAddr(uint32_t src_ip_addr, uint32_t dst_ip_addr) {
+
+ src_ip_addr = ntohl(src_ip_addr);
+ dst_ip_addr = ntohl(dst_ip_addr);
+ if ((src_ip_addr & LOOPBACK_MASK) == LOOPBACK_ADDR || (dst_ip_addr & LOOPBACK_MASK) == LOOPBACK_ADDR) /* (loopback) */
+ return true;
+ return false;
+}
+
+void IPACM_ConntrackListener::readConntrack() {
+
+ IPACM_ConntrackClient *pClient;
+ int len_fil = 0, recv_bytes = -1, index = 0, len =0;
+ char buffer[CT_ENTRIES_BUFFER_SIZE];
+ char *buf = &buffer[0];
+ struct nf_conntrack *ct;
+ struct nlmsghdr *nl_header;
+ static struct sockaddr_nl nlAddr = {
+ .nl_family = AF_NETLINK
+ };
+ unsigned int addr_len = sizeof(nlAddr);
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ len = MAX_CONNTRACK_ENTRIES * sizeof(struct nf_conntrack **);
+
+ ct_entries = (struct nf_conntrack **) malloc(len);
+ memset(ct_entries, 0, len);
+
+ if( pClient->fd_tcp < 0)
+ {
+ IPACMDBG_H("Invalid fd %d \n",pClient->fd_tcp);
+ return;
+ }
+
+ IPACMDBG_H("receiving conntrack entries started.\n");
+ while(len_fil < sizeof(buffer) && index < MAX_CONNTRACK_ENTRIES)
+ {
+ recv_bytes = recvfrom( pClient->fd_tcp, buf, sizeof(buffer)-len_fil, 0, (struct sockaddr *)&nlAddr, (socklen_t *)&addr_len);
+ if(recv_bytes < 0)
+ {
+ IPACMDBG_H("error in receiving conntrack entries %d%s",errno, strerror(errno));
+ break;
+ }
+ else
+ {
+ nl_header = (struct nlmsghdr *)buf;
+
+ if (NLMSG_OK(nl_header, recv_bytes) == 0 || nl_header->nlmsg_type == NLMSG_ERROR)
+ {
+ IPACMDBG_H("recv_bytes is %d\n",recv_bytes);
+ break;
+ }
+ ct = nfct_new();
+ if (ct != NULL)
+ {
+ int parseResult = nfct_parse_conntrack((nf_conntrack_msg_type) NFCT_T_ALL,nl_header, ct);
+ if(parseResult != NFCT_T_ERROR)
+ {
+ ct_entries[index++] = ct;
+ }
+ else
+ {
+ IPACMDBG_H("error in parsing %d%s \n", errno, strerror(errno));
+ }
+ }
+ else
+ {
+ IPACMDBG_H("ct allocation failed");
+ continue;
+ }
+
+ if((nl_header->nlmsg_type & NLM_F_MULTI) == 0)
+ {
+ break;
+ }
+ len_fil += recv_bytes;
+ buf = buf + recv_bytes;
+ }
+ }
+ isReadCTDone = true;
+ IPACMDBG_H("receiving conntrack entries ended.\n");
+ if(isWanUp() && !isProcessCTDone)
+ {
+ IPACMDBG_H("wan is up, process ct entries \n");
+ processConntrack();
+ }
+
+ return ;
+}
+
+void IPACM_ConntrackListener::processConntrack() {
+
+ uint8_t ip_type;
+ int index = 0;
+ ipacm_ct_evt_data *ct_data;
+ enum nf_conntrack_msg_type type = NFCT_T_ALL;
+ IPACMDBG_H("process conntrack started \n");
+ if(ct_entries != NULL)
+ {
+ while(ct_entries[index] != NULL)
+ {
+ ip_type = nfct_get_attr_u8(ct_entries[index], ATTR_REPL_L3PROTO);
+ if(!(AF_INET6 == ip_type) && isLocalHostAddr(nfct_get_attr_u32(ct_entries[index], ATTR_ORIG_IPV4_SRC),
+ nfct_get_attr_u32(ct_entries[index], ATTR_ORIG_IPV4_DST)))
+ {
+ IPACMDBG_H(" loopback entry \n");
+ goto IGNORE;
+ }
+
+#ifndef CT_OPT
+ if(AF_INET6 == ip_type)
+ {
+ IPACMDBG("Ignoring ipv6(%d) connections\n", ip_type);
+ goto IGNORE;
+ }
+#endif
+
+ ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
+ if(ct_data == NULL)
+ {
+ IPACMERR("unable to allocate memory \n");
+ goto IGNORE;
+ }
+
+ ct_data->ct = ct_entries[index];
+ ct_data->type = type;
+
+#ifdef CT_OPT
+ if(AF_INET6 == ip_type)
+ {
+ ProcessCTV6Message(ct_data);
+ }
+#else
+ ProcessCTMessage(ct_data);
+#endif
+ index++;
+ free(ct_data);
+ continue;
+IGNORE:
+ nfct_destroy(ct_entries[index]);
+ index++;
+ }
+ }
+ else
+ {
+ IPACMDBG_H("ct entry is null\n");
+ return ;
+ }
+ isProcessCTDone = true;
+ free(ct_entries);
+ IPACMDBG_H("process conntrack ended \n");
+ return;
+}